Merge branch 'develop' into accessible_ui

This commit is contained in:
Martin Raifer
2021-12-07 16:06:56 +01:00
140 changed files with 2047 additions and 878 deletions
+6
View File
@@ -6,3 +6,9 @@ contact_links:
- name: There is an issue with brand icons or brand tagging recommendations.
url: https://github.com/osmlab/name-suggestion-index/issues
about: Please create a feature request in the name-suggestion-index repository.
- name: There is an issue with a background imagery source.
url: https://github.com/osmlab/editor-layer-index/issues
about: Please create an issue in the editor-layer-index repository.
- name: You have a general question or want to discuss something.
url: https://github.community/
about: Please ask and answer questions in iD's Discussions tab.
+1 -1
View File
@@ -262,7 +262,7 @@ iD's preset database is stored in the `iD.fileFetcher.cache().presets` object an
or modified prior to creating the iD context.
The format of the `presets` object is
[documented here](https://github.com/openstreetmap/iD/tree/develop/data/presets#custom-presets).
[documented as part of the schema-builder project](https://github.com/ideditor/schema-builder#presets).
To add a new preset to iD's existing preset database.
```js
+25
View File
@@ -14,6 +14,7 @@ _Breaking developer changes, which may affect downstream projects or sites that
##### YYYY-MMM-DD
#### :newspaper: News
#### :shield: Security
#### :mega: Release Highlights
#### :boom: Breaking Changes
#### :tada: New Features
@@ -41,10 +42,16 @@ _Breaking developer changes, which may affect downstream projects or sites that
#### :newspaper: News
* We maintain a running changelog now! Upcoming changes will be added to the _[Unreleased](#Unreleased)_ section of this changelog as soon as they are ready in the [development version](https://ideditor.netlify.app/) of the iD editor. ([#8805])
#### :shield: Security
* Fix missing escaping of external texts and content such as OSM user names, OSM tags, etc. which had opened a way to inject arbitrary HTML into the iD editor, potentially making XSS attacks possible. ([#8813])
#### :boom: Breaking Changes
#### :tada: New Features
#### :sparkles: Usability & Accessibility
* Add a preview to colour fields, showing a native colour picker dialog on click ([#8782], thanks [@k-yle])
* Tag keys of a multi-selection can now also be changed in the tags editor when the tag values differ in the selected features. ([#8836])
#### :scissors: Operations
* Split operation now indicates more clearly when multiple ways will be affected and gives a hint how to restrict the operation to a single line ([#8818])
* Many operations now better preserve OSM object history ([#8839], thanks [@tpetillon])
#### :camera: Street-Level
* Rename OpenStreetCam overlay to KartaView ([#8807])
#### :white_check_mark: Validation
@@ -53,24 +60,42 @@ _Breaking developer changes, which may affect downstream projects or sites that
#### :bug: Bugfixes
* Fix hidden tooltips on map control toolbar ([#8781])
* Fix glitching out turn restriction minimap on narrow sidebars ([#8792])
* Fix non-string properties of GeoJSON custom map data not being displayed correctly ([#8825], thanks [@k-yle])
* Fix a bug which made it impossible to switch to a custom TMS imagery layer after using a custom WMS source and vice versa ([#8057])
* Fix a bug where the validator might show wrong tagging suggestions for a preset if another preset has a partial match ([#8828], thanks [@bhousel])
* Show correct vintage and other metadata for "Esri World Imagery"'s higher zoom levels
* Fix wrong order of route relation members after a split operation ([#8519], thanks [@tpetillon])
#### :earth_asia: Localization
* Deprecate ~`t.html`~ for providing localized texts, which is replaced by the new method `t.append` which directly and safely appends the localized strings to the DOM ([#8817])
#### :hourglass: Performance
#### :mortar_board: Walkthrough / Help
* Show privacy settings in splash screen (i.e. the "Welcome to iD" message) ([#8831])
#### :rocket: Presets
* Radio-button based presets fields can be in an non-unique state (e.g. a tunnel which is also a ford) this is now rendered like a multi selection with conflicting states ([#8796])
* Add colours for preset categories ([#8799])
#### :hammer: Development
[#8057]: https://github.com/openstreetmap/iD/issues/8057
[#8519]: https://github.com/openstreetmap/iD/issues/8519
[#8771]: https://github.com/openstreetmap/iD/issues/8771
[#8781]: https://github.com/openstreetmap/iD/issues/8781
[#8782]: https://github.com/openstreetmap/iD/pull/8782
[#8792]: https://github.com/openstreetmap/iD/pull/8792
[#8796]: https://github.com/openstreetmap/iD/issues/8796
[#8799]: https://github.com/openstreetmap/iD/issues/8799
[#8800]: https://github.com/openstreetmap/iD/pull/8800
[#8805]: https://github.com/openstreetmap/iD/issues/8805
[#8807]: https://github.com/openstreetmap/iD/issues/8807
[#8813]: https://github.com/openstreetmap/iD/issues/8813
[#8817]: https://github.com/openstreetmap/iD/pull/8817
[#8818]: https://github.com/openstreetmap/iD/issues/8818
[#8825]: https://github.com/openstreetmap/iD/pull/8825
[#8828]: https://github.com/openstreetmap/iD/pull/8828
[#8831]: https://github.com/openstreetmap/iD/issues/8831
[#8836]: https://github.com/openstreetmap/iD/issues/8836
[#8839]: https://github.com/openstreetmap/iD/pull/8839
[@k-yle]: https://github.com/k-yle
[@tpetillon]: https://github.com/tpetillon
# 2.20.2
##### 2021-Oct-28
+50 -7
View File
@@ -194,7 +194,8 @@ input[type=number],
input[type=url],
input[type=tel],
input[type=email],
input[type=date] {
input[type=date],
input[type=color] {
/* need this since line-height interpretation may vary by font or browser */
height: 2.585em;
}
@@ -1510,6 +1511,34 @@ a.hide-toggle {
fill: #333;
opacity: .5;
}
.form-field-button.colour-preview {
border-radius: 0 0 4px 0;
}
.form-field-button.colour-preview > div.colour-box {
border: 3px solid #fff;
height: 100%;
border-radius: 8px;
cursor: pointer;
text-align: center;
line-height: 20px;
padding: 1px 0 0 1px;
}
.inspector-hover .form-field-button.colour-preview > div.colour-box {
border-color: #ececec;
}
.form-field-button.colour-preview:active > div.colour-box,
.form-field-button.colour-preview:focus > div.colour-box {
border-color: #f1f1f1;
}
@media (hover: hover) {
.form-field-button.colour-preview:hover > div.colour-box {
border-color: #f1f1f1;
}
}
.form-field-button.colour-selector {
visibility: hidden;
position: absolute;
}
/* round corners of first/last child elements */
@@ -1708,12 +1737,13 @@ a.hide-toggle {
/* Field - Text / Numeric
------------------------------------------------------- */
.form-field-input-text > input:only-of-type,
.form-field-input-text > input:only-child,
.form-field-input-tel > input:only-of-type,
.form-field-input-email > input:only-of-type,
.form-field-input-url > input:only-child {
border-radius: 0 0 4px 4px;
}
.form-field-input-text > input:not(:only-child),
.form-field-input-url > input:not(:only-child) {
border-radius: 0 0 0 4px;
}
@@ -4941,6 +4971,14 @@ img.tile-debug {
color: #7092ff;
}
.modal-splash .section-preferences-third-party {
margin-top: 20px;
}
.modal-splash .section-preferences-third-party .privacy-link {
display: none;
}
/* Shortcuts Modal
------------------------------------------------------- */
@@ -5353,22 +5391,26 @@ button.conflicts-button {
/* dark tooltips for sidebar / panels */
.tooltip.dark.top .popover-arrow,
.map-pane .tooltip.top .popover-arrow,
.sidebar .tooltip.top .popover-arrow {
.sidebar .tooltip.top .popover-arrow,
.modal .tooltip.top .popover-arrow {
border-top-color: #000;
}
.tooltip.dark.bottom .popover-arrow,
.map-pane .tooltip.bottom .popover-arrow,
.sidebar .tooltip.bottom .popover-arrow {
.sidebar .tooltip.bottom .popover-arrow,
.modal .tooltip.bottom .popover-arrow {
border-bottom-color: #000;
}
.tooltip.dark.left .popover-arrow,
.map-pane .tooltip.left .popover-arrow,
.sidebar .tooltip.left .popover-arrow {
.sidebar .tooltip.left .popover-arrow,
.modal .tooltip.left .popover-arrow {
border-left-color: #000;
}
.tooltip.dark.right .popover-arrow,
.map-pane .tooltip.right .popover-arrow,
.sidebar .tooltip.right .popover-arrow {
.sidebar .tooltip.right .popover-arrow,
.modal .tooltip.right .popover-arrow {
border-right-color: #000;
}
.tooltip.dark .popover-inner,
@@ -5379,7 +5421,8 @@ button.conflicts-button {
.map-pane .keyhint-wrap,
.sidebar .popover-inner,
.sidebar .tooltip-heading,
.sidebar .keyhint-wrap {
.sidebar .keyhint-wrap,
.modal .popover-inner {
background: #000;
color: #ccc;
}
+7 -4
View File
@@ -474,8 +474,8 @@ en:
single_node: Divide this line into two at this point.
multiple_node: Divide this line at these points.
multiple:
single_node: Divide these lines at this point.
multiple_node: Divide these lines at these points.
single_node: "Divide all lines at this point. Tip: To limit this operation to a specific line, select both the line and point before performing the split."
multiple_node: "Divide all lines at these points. Tip: To limit this operation to a specific line, select the line as well as the points before performing the split."
area:
single:
single_node: Divide the edge of this area into two at this point.
@@ -649,8 +649,10 @@ en:
last_edit: Last Edit
edited_by: Edited By
changeset: Changeset
changeset_link: Changeset on osm.org
profile_link: Profile on osm.org
history_link: History on osm.org
unknown: Unknown
link_text: History on openstreetmap.org
note_no_history: "No History (New Note)"
note_comments: Comments
note_created_date: Created Date
@@ -1010,7 +1012,7 @@ en:
location: 'This feature was moved by both you and {user}.'
nodelist: 'Nodes were changed by both you and {user}.'
memberlist: 'Relation members were changed by both you and {user}.'
tags: 'You changed the <b>{tag}</b> tag to "{local}" and {user} changed it to "{remote}".'
tags: 'You changed the "{tag}" tag to "{local}" and {user} changed it to "{remote}".'
success:
just_edited: "You just edited OpenStreetMap!"
thank_you: "Thank you for improving the map."
@@ -1038,6 +1040,7 @@ en:
privacy_update: "Our privacy policy has recently been updated."
privacy_policy: iD privacy policy
privacy: "{updateMessage} By using this software, you agree to do so in accordance with the {privacyLink}."
privacy_settings: Your Privacy Settings
walkthrough: "Start the Walkthrough"
start: "Edit now"
source_switch:
+1 -1
View File
File diff suppressed because one or more lines are too long
+16 -7
View File
@@ -32,7 +32,7 @@ export function actionAddMember(relationId, member, memberIndex, insertPair) {
// Add a way member into the relation "wherever it makes sense".
// In this situation we were not supplied a memberIndex.
function addWayMember(relation, graph) {
var groups, tempWay, item, i, j, k;
var groups, tempWay, insertPairIsReversed, item, i, j, k;
// remove PTv2 stops and platforms before doing anything.
var PTv2members = [];
@@ -65,6 +65,14 @@ export function actionAddMember(relationId, member, memberIndex, insertPair) {
groups = utilArrayGroupBy(tempRelation.members, 'type');
groups.way = groups.way || [];
// Insert pair is reversed if the inserted way comes before the original one.
// (Except when they form a loop.)
var originalWay = graph.entity(insertPair.originalID);
var insertedWay = graph.entity(insertPair.insertedID);
insertPairIsReversed = originalWay.nodes.length > 0 && insertedWay.nodes.length > 0 &&
insertedWay.nodes[insertedWay.nodes.length - 1] === originalWay.nodes[0] &&
originalWay.nodes[originalWay.nodes.length - 1] !== insertedWay.nodes[0];
} else {
// Add the member anywhere, one time. Just push and let `osmJoinWays` decide where to put it.
groups = utilArrayGroupBy(relation.members, 'type');
@@ -96,16 +104,17 @@ export function actionAddMember(relationId, member, memberIndex, insertPair) {
// If this is a paired item, generate members in correct order and role
if (tempWay && item.id === tempWay.id) {
if (nodes[0].id === insertPair.nodes[0]) {
item.pair = [
{ id: insertPair.originalID, type: 'way', role: item.role },
{ id: insertPair.insertedID, type: 'way', role: item.role }
];
} else {
var reverse = nodes[0].id !== insertPair.nodes[0] ^ insertPairIsReversed;
if (reverse) {
item.pair = [
{ id: insertPair.insertedID, type: 'way', role: item.role },
{ id: insertPair.originalID, type: 'way', role: item.role }
];
} else {
item.pair = [
{ id: insertPair.originalID, type: 'way', role: item.role },
{ id: insertPair.insertedID, type: 'way', role: item.role }
];
}
}
+17 -10
View File
@@ -1,12 +1,12 @@
import { actionDeleteNode } from './delete_node';
import { actionDeleteWay } from './delete_way';
import { utilArrayUniq } from '../util';
import { utilArrayUniq, utilOldestID } from '../util';
// Connect the ways at the given nodes.
//
// First choose a node to be the survivor, with preference given
// to an existing (not new) node.
// to the oldest existing (not new) and "interesting" node.
//
// Tags and relation memberships of of non-surviving nodes are merged
// to the survivor.
@@ -24,11 +24,21 @@ export function actionConnect(nodeIDs) {
var parents;
var i, j;
// Choose a survivor node, prefer an existing (not new) node - #4974
// Select the node with the ID passed as parameter if it is in the list,
// otherwise select the node with the oldest ID as the survivor, or the
// last one if there are only new nodes.
nodeIDs.reverse();
var interestingIDs = [];
for (i = 0; i < nodeIDs.length; i++) {
survivor = graph.entity(nodeIDs[i]);
if (survivor.version) break; // found one
node = graph.entity(nodeIDs[i]);
if (node.hasInterestingTags()) {
if (!node.isNew()) {
interestingIDs.push(node.id);
}
}
}
survivor = graph.entity(utilOldestID(interestingIDs.length > 0 ? interestingIDs : nodeIDs));
// Replace all non-surviving nodes with the survivor and merge tags.
for (i = 0; i < nodeIDs.length; i++) {
@@ -71,11 +81,8 @@ export function actionConnect(nodeIDs) {
var relations, relation, role;
var i, j, k;
// Choose a survivor node, prefer an existing (not new) node - #4974
for (i = 0; i < nodeIDs.length; i++) {
survivor = graph.entity(nodeIDs[i]);
if (survivor.version) break; // found one
}
// Select the node with the oldest ID as the survivor.
survivor = graph.entity(utilOldestID(nodeIDs));
// 1. disable if the nodes being connected have conflicting relation roles
for (i = 0; i < nodeIDs.length; i++) {
+6 -12
View File
@@ -3,7 +3,7 @@ import { actionDeleteWay } from './delete_way';
import { osmIsInterestingTag } from '../osm/tags';
import { osmJoinWays } from '../osm/multipolygon';
import { geoPathIntersections } from '../geo';
import { utilArrayGroupBy, utilArrayIdentical, utilArrayIntersection } from '../util';
import { utilArrayGroupBy, utilArrayIdentical, utilArrayIntersection, utilOldestID } from '../util';
// Join ways at the end node they share.
@@ -28,6 +28,11 @@ export function actionJoin(ids) {
var action = function(graph) {
var ways = ids.map(graph.entity, graph);
// Prefer to keep an existing way.
// if there are multiple existing ways, keep the oldest one
// the oldest way is determined by the ID of the way.
var survivorID = utilOldestID(ways.map(way => way.id));
// if any of the ways are sided (e.g. coastline, cliff, kerb)
// sort them first so they establish the overall order - #6033
ways.sort(function(a, b) {
@@ -38,17 +43,6 @@ export function actionJoin(ids) {
: 0;
});
// Prefer to keep an existing way.
// if there are multiple existing ways, keep the oldest one
// the oldest way is determined by the ID of the way
const survivorID = (
ways
.filter((way) => !way.isNew())
.sort((a, b) => +a.osmId() - +b.osmId())[0] || ways[0]
).id;
var sequences = osmJoinWays(ways, graph);
var joined = sequences[0];
+58 -14
View File
@@ -1,5 +1,5 @@
import { osmTagSuggestingArea } from '../osm/tags';
import { utilArrayGroupBy, utilArrayUniq } from '../util';
import { utilArrayGroupBy, utilArrayUniq, utilCompareIDs } from '../util';
export function actionMerge(ids) {
@@ -29,21 +29,65 @@ export function actionMerge(ids) {
var nodes = utilArrayUniq(graph.childNodes(target));
var removeNode = point;
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (graph.parentWays(node).length > 1 ||
graph.parentRelations(node).length ||
node.hasInterestingTags()) {
continue;
if (!point.isNew()) {
// Try to preserve the original point if it already has
// an ID in the database.
var inserted = false;
var canBeReplaced = function(node) {
return !(graph.parentWays(node).length > 1 ||
graph.parentRelations(node).length);
};
var replaceNode = function(node) {
graph = graph.replace(point.update({ tags: node.tags, loc: node.loc }));
target = target.replaceNode(node.id, point.id);
graph = graph.replace(target);
removeNode = node;
inserted = true;
};
var i;
var node;
// First, try to replace a new child node on the target way.
for (i = 0; i < nodes.length; i++) {
node = nodes[i];
if (canBeReplaced(node) && node.isNew()) {
replaceNode(node);
break;
}
}
// Found an uninteresting child node on the target way.
// Move orig point into its place to preserve point's history. #3683
graph = graph.replace(point.update({ tags: {}, loc: node.loc }));
target = target.replaceNode(node.id, point.id);
graph = graph.replace(target);
removeNode = node;
break;
if (!inserted && point.hasInterestingTags()) {
// No new child node found, try to find an existing, but
// uninteresting child node instead.
for (i = 0; i < nodes.length; i++) {
node = nodes[i];
if (canBeReplaced(node) &&
!node.hasInterestingTags()) {
replaceNode(node);
break;
}
}
if (!inserted) {
// Still not inserted, try to find an existing, interesting,
// but more recent child node.
for (i = 0; i < nodes.length; i++) {
node = nodes[i];
if (canBeReplaced(node) &&
utilCompareIDs(point.id, node.id) < 0) {
replaceNode(node);
break;
}
}
}
// If the point still hasn't been inserted, we give up.
// There are more interesting or older nodes on the way.
}
}
graph = graph.remove(removeNode);
+15 -7
View File
@@ -1,6 +1,6 @@
import { geoPolygonContainsPolygon } from '../geo';
import { osmJoinWays, osmRelation } from '../osm';
import { utilArrayGroupBy, utilArrayIntersection, utilObjectOmit } from '../util';
import { utilArrayGroupBy, utilArrayIntersection, utilObjectOmit, utilOldestID } from '../util';
export function actionMergePolygon(ids, newRelationId) {
@@ -85,13 +85,21 @@ export function actionMergePolygon(ids, newRelationId) {
outer = !outer;
}
// Move all tags to one relation
var relation = entities.multipolygon[0] ||
osmRelation({ id: newRelationId, tags: { type: 'multipolygon' }});
// Move all tags to one relation.
// Keep the oldest multipolygon alive if it exists.
var relation;
if (entities.multipolygon.length > 0) {
var oldestID = utilOldestID(entities.multipolygon.map((entity) => entity.id));
relation = entities.multipolygon.find((entity) => entity.id === oldestID);
} else {
relation = osmRelation({ id: newRelationId, tags: { type: 'multipolygon' }});
}
entities.multipolygon.slice(1).forEach(function(m) {
relation = relation.mergeTags(m.tags);
graph = graph.remove(m);
entities.multipolygon.forEach(function(m) {
if (m.id !== relation.id) {
relation = relation.mergeTags(m.tags);
graph = graph.remove(m);
}
});
entities.closedWay.forEach(function(way) {
+9 -9
View File
@@ -1,5 +1,6 @@
import deepEqual from 'fast-deep-equal';
import { diff3Merge } from 'node-diff3';
import { escape } from 'lodash';
import { t } from '../core/localizer';
import { actionDeleteMultiple } from './delete_multiple';
@@ -14,7 +15,7 @@ export function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTag
function user(d) {
return (typeof formatUser === 'function') ? formatUser(d) : d;
return (typeof formatUser === 'function') ? formatUser(d) : escape(d);
}
@@ -31,7 +32,7 @@ export function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTag
return target.update({loc: remote.loc});
}
_conflicts.push(t('merge_remote_changes.conflict.location', { user: user(remote.user) }));
_conflicts.push(t.html('merge_remote_changes.conflict.location', { user: { html: user(remote.user) } }));
return target;
}
@@ -64,7 +65,7 @@ export function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTag
} else if (deepEqual(c.o, c.b)) { // only changed locally
nodes.push.apply(nodes, c.a);
} else { // changed both locally and remotely
_conflicts.push(t('merge_remote_changes.conflict.nodelist', { user: user(remote.user) }));
_conflicts.push(t.html('merge_remote_changes.conflict.nodelist', { user: { html: user(remote.user) } }));
break;
}
}
@@ -118,7 +119,7 @@ export function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTag
if (remote.visible) {
target = mergeLocation(remote, target);
} else {
_conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
_conflicts.push(t.html('merge_remote_changes.conflict.deleted', { user: { html: user(remote.user) } }));
}
if (_conflicts.length !== ccount) break;
@@ -149,7 +150,7 @@ export function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTag
return target.update({members: remote.members});
}
_conflicts.push(t('merge_remote_changes.conflict.memberlist', { user: user(remote.user) }));
_conflicts.push(t.html('merge_remote_changes.conflict.memberlist', { user: { html: user(remote.user) } }));
return target;
}
@@ -176,9 +177,8 @@ export function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTag
if (o[k] !== b[k] && a[k] !== b[k]) { // changed remotely..
if (o[k] !== a[k]) { // changed locally..
_conflicts.push(t('merge_remote_changes.conflict.tags',
{ tag: k, local: a[k], remote: b[k], user: user(remote.user) }));
_conflicts.push(t.html('merge_remote_changes.conflict.tags',
{ tag: k, local: a[k], remote: b[k], user: { html: user(remote.user) } }));
} else { // unchanged locally, accept remote change..
if (b.hasOwnProperty(k)) {
tags[k] = b[k];
@@ -224,7 +224,7 @@ export function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTag
return graph.replace(target);
} else {
_conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
_conflicts.push(t.html('merge_remote_changes.conflict.deleted', { user: { html: user(remote.user) } }));
return graph; // do nothing
}
}
+4 -4
View File
@@ -447,7 +447,7 @@ export function behaviorDrawWay(context, wayID, mode, startGraph) {
context.ui().flash
.duration(4000)
.iconName('#iD-icon-no')
.label(t('operations.follow.error.needs_more_initial_nodes'))();
.label(t.html('operations.follow.error.needs_more_initial_nodes'))();
return;
}
@@ -461,7 +461,7 @@ export function behaviorDrawWay(context, wayID, mode, startGraph) {
context.ui().flash
.duration(4000)
.iconName('#iD-icon-no')
.label(t(`operations.follow.error.intersection_of_multiple_ways.${featureType}`))();
.label(t.html(`operations.follow.error.intersection_of_multiple_ways.${featureType}`))();
return;
}
@@ -472,7 +472,7 @@ export function behaviorDrawWay(context, wayID, mode, startGraph) {
context.ui().flash
.duration(4000)
.iconName('#iD-icon-no')
.label(t(`operations.follow.error.intersection_of_different_ways.${featureType}`))();
.label(t.html(`operations.follow.error.intersection_of_different_ways.${featureType}`))();
return;
}
@@ -501,7 +501,7 @@ export function behaviorDrawWay(context, wayID, mode, startGraph) {
context.ui().flash
.duration(4000)
.iconName('#iD-icon-no')
.label(t('operations.follow.error.unknown'))();
.label(t.html('operations.follow.error.unknown'))();
}
}
+35 -5
View File
@@ -1,3 +1,5 @@
import { escape } from 'lodash-es';
import { fileFetcher } from './file_fetcher';
import { utilDetect } from '../util/detect';
import { utilStringQs } from '../util';
@@ -347,14 +349,42 @@ export function coreLocalizer() {
};
// Returns the localized text wrapped in an HTML element encoding the locale info
/**
* @deprecated This method is considered deprecated. Instead, use the direct DOM manipulating
* method `t.append`.
*/
localizer.t.html = function(stringId, replacements, locale) {
const info = localizer.tInfo(stringId, replacements, locale);
// text may be empty or undefined if `replacements.default` is
return info.text ? localizer.htmlForLocalizedText(info.text, info.locale) : '';
// replacement string might be html unsafe, so we need to escape it except if it is explicitly marked as html code
replacements = Object.assign({}, replacements);
for (var k in replacements) {
if (typeof replacements[k] === 'string') {
replacements[k] = escape(replacements[k]);
}
if (typeof replacements[k] === 'object' && typeof replacements[k].html === 'string') {
replacements[k] = replacements[k].html;
}
}
const info = localizer.tInfo(stringId, replacements, locale);
// text may be empty or undefined if `replacements.default` is
if (info.text) {
return `<span class="localized-text" lang="${info.locale || 'und'}">${info.text}</span>`;
} else {
return '';
}
};
localizer.htmlForLocalizedText = function(text, localeCode) {
return `<span class="localized-text" lang="${localeCode || 'unknown'}">${text}</span>`;
// Adds localized text wrapped as an HTML span element with locale info to the DOM
localizer.t.append = function(stringId, replacements, locale) {
return function(selection) {
const info = localizer.tInfo(stringId, replacements, locale);
return selection.append('span')
.attr('class', 'localized-text')
.attr('lang', info.locale || 'und')
.text((replacements && replacements.prefix || '')
+ info.text
+ (replacements &&replacements.suffix || ''));
};
};
localizer.languageName = (code, options) => {
+12 -3
View File
@@ -12,6 +12,8 @@ _storage = _storage || (() => {
};
})();
const _listeners = {};
//
// corePreferences is an interface for persisting basic key-value strings
// within and between iD sessions on the same site.
@@ -22,11 +24,13 @@ _storage = _storage || (() => {
* @returns {boolean} true if the action succeeded
*/
function corePreferences(k, v) {
try {
if (arguments.length === 1) return _storage.getItem(k);
if (v === undefined) return _storage.getItem(k);
else if (v === null) _storage.removeItem(k);
else _storage.setItem(k, v);
if (_listeners[k]) {
_listeners[k].forEach(handler => handler(v));
}
return true;
} catch (e) {
/* eslint-disable no-console */
@@ -36,7 +40,12 @@ function corePreferences(k, v) {
/* eslint-enable no-console */
return false;
}
}
// adds an event listener which is triggered whenever
corePreferences.onChange = function(k, handler) {
_listeners[k] = _listeners[k] || [];
_listeners[k].push(handler);
};
export { corePreferences as prefs };
+2 -1
View File
@@ -1,4 +1,5 @@
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { escape } from 'lodash-es';
import { fileFetcher } from './file_fetcher';
import { actionDiscardTags } from '../actions/discard_tags';
@@ -218,7 +219,7 @@ export function coreUploader(context) {
};
}
function formatUser(d) {
return '<a href="' + osm.userURL(d) + '" target="_blank">' + d + '</a>';
return '<a href="' + osm.userURL(d) + '" target="_blank">' + escape(d) + '</a>';
}
function entityName(entity) {
return utilDisplayName(entity) || (utilDisplayType(entity.id) + ' ' + entity.id);
+2 -2
View File
@@ -239,7 +239,7 @@ export function modeDragNode(context) {
context.ui().flash
.duration(4000)
.iconName('#iD-icon-no')
.label(t('operations.connect.' + isInvalid,
.label(t.html('operations.connect.' + isInvalid,
{ relation: presetManager.item('type/restriction').name() }
))();
}
@@ -248,7 +248,7 @@ export function modeDragNode(context) {
context.ui().flash
.duration(3000)
.iconName('#iD-icon-no')
.label(t('self_intersection.error.' + errorID))();
.label(t.html('self_intersection.error.' + errorID))();
} else {
if (nope) { // about to un-nope, remove hint
context.ui().flash
+1 -1
View File
@@ -12,7 +12,7 @@ export function modeDrawArea(context, wayID, startGraph, button) {
.on('rejectedSelfIntersection.modeDrawArea', function() {
context.ui().flash
.iconName('#iD-icon-no')
.label(t('self_intersection.error.areas'))();
.label(t.html('self_intersection.error.areas'))();
});
mode.wayID = wayID;
+1 -1
View File
@@ -12,7 +12,7 @@ export function modeDrawLine(context, wayID, startGraph, button, affix, continui
.on('rejectedSelfIntersection.modeDrawLine', function() {
context.ui().flash
.iconName('#iD-icon-no')
.label(t('self_intersection.error.lines'))();
.label(t.html('self_intersection.error.lines'))();
});
mode.wayID = wayID;
+1 -1
View File
@@ -400,7 +400,7 @@ export function modeSelect(context, selectedIDs) {
.duration(4000)
.iconName('#iD-icon-no')
.iconClass('operation disabled')
.label(t('operations.scale.' + disabled + '.' + multi))();
.label(t.html('operations.scale.' + disabled + '.' + multi))();
} else {
const pivot = context.projection(extent.center());
const annotation = t('operations.scale.annotation.' + (isUp ? 'up' : 'down') + '.feature', { n: selectedIDs.length });
+9
View File
@@ -78,6 +78,15 @@ export function operationSplit(context, selectedIDs) {
};
operation.icon = function() {
if (_waysAmount === 'multiple') {
return '#iD-operation-split-multiple';
} else {
return '#iD-operation-split';
}
};
operation.id = 'split';
operation.keys = [t('operations.split.key')];
operation.title = t('operations.split.title');
+7 -2
View File
@@ -36,7 +36,11 @@ osmEntity.id.fromOSM = function(type, id) {
osmEntity.id.toOSM = function(id) {
return id.slice(1);
var match = id.match(/^[cnwr](-?\d+)$/);
if (match) {
return match[1];
}
return '';
};
@@ -129,7 +133,8 @@ osmEntity.prototype = {
isNew: function() {
return this.osmId() < 0;
var osmId = osmEntity.id.toOSM(this.id);
return osmId.length === 0 || osmId[0] === '-';
},
+51 -85
View File
@@ -1,5 +1,6 @@
import { geoArea as d3_geoArea, geoMercatorRaw as d3_geoMercatorRaw } from 'd3-geo';
import { json as d3_json } from 'd3-fetch';
import { escape } from 'lodash';
import { t, localizer } from '../core/localizer';
import { geoExtent, geoSphericalDistance } from '../geo';
@@ -68,19 +69,19 @@ export function rendererBackgroundSource(data) {
source.name = function() {
var id_safe = source.id.replace(/\./g, '<TX_DOT>');
return t('imagery.' + id_safe + '.name', { default: _name });
return t('imagery.' + id_safe + '.name', { default: escape(_name) });
};
source.label = function() {
var id_safe = source.id.replace(/\./g, '<TX_DOT>');
return t.html('imagery.' + id_safe + '.name', { default: _name });
return t.html('imagery.' + id_safe + '.name', { default: escape(_name) });
};
source.description = function() {
var id_safe = source.id.replace(/\./g, '<TX_DOT>');
return t.html('imagery.' + id_safe + '.description', { default: _description });
return t.html('imagery.' + id_safe + '.description', { default: escape(_description) });
};
@@ -442,42 +443,22 @@ rendererBackgroundSource.Esri = function(data) {
esri.getMetadata = function(center, tileCoord, callback) {
if (esri.id !== 'EsriWorldImagery') {
// rest endpoint is not available for ESRI's "clarity" imagery
return callback(null, {});
}
var tileID = tileCoord.slice(0, 3).join('/');
var zoom = Math.min(tileCoord[2], esri.zoomExtent[1]);
var centerPoint = center[0] + ',' + center[1]; // long, lat (as it should be)
var unknown = t('info_panels.background.unknown');
var metadataLayer;
var vintage = {};
var metadata = {};
if (inflight[tileID]) return;
switch (true) {
case (zoom >= 20 && esri.id === 'EsriWorldImageryClarity'):
metadataLayer = 4;
break;
case zoom >= 19:
metadataLayer = 3;
break;
case zoom >= 17:
metadataLayer = 2;
break;
case zoom >= 13:
metadataLayer = 0;
break;
default:
metadataLayer = 99;
}
var url;
// build up query using the layer appropriate to the current zoom
if (esri.id === 'EsriWorldImagery') {
url = 'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/';
} else if (esri.id === 'EsriWorldImageryClarity') {
url = 'https://serviceslab.arcgisonline.com/arcgis/rest/services/Clarity_World_Imagery/MapServer/';
}
url += metadataLayer + '/query?returnGeometry=false&geometry=' + centerPoint + '&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json';
var url = 'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/4/query';
url += '?returnGeometry=false&geometry=' + centerPoint + '&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json';
if (!cache[tileID]) {
cache[tileID] = {};
@@ -486,67 +467,52 @@ rendererBackgroundSource.Esri = function(data) {
return callback(null, cache[tileID].metadata);
}
// accurate metadata is only available >= 13
if (metadataLayer === 99) {
vintage = {
start: null,
end: null,
range: null
};
metadata = {
vintage: null,
source: unknown,
description: unknown,
resolution: unknown,
accuracy: unknown
};
inflight[tileID] = true;
d3_json(url)
.then(function(result) {
delete inflight[tileID];
callback(null, metadata);
result = result.features.map(f => f.attributes)
.filter(a => a.MinMapLevel <= zoom && a.MaxMapLevel >= zoom)[0];
} else {
inflight[tileID] = true;
d3_json(url)
.then(function(result) {
delete inflight[tileID];
if (!result) {
throw new Error('Unknown Error');
} else if (result.features && result.features.length < 1) {
throw new Error('No Results');
} else if (result.error && result.error.message) {
throw new Error(result.error.message);
}
if (!result) {
throw new Error('Unknown Error');
} else if (result.features && result.features.length < 1) {
throw new Error('No Results');
} else if (result.error && result.error.message) {
throw new Error(result.error.message);
}
// pass through the discrete capture date from metadata
var captureDate = localeDateString(result.features[0].attributes.SRC_DATE2);
vintage = {
start: captureDate,
end: captureDate,
range: captureDate
};
metadata = {
vintage: vintage,
source: clean(result.features[0].attributes.NICE_NAME),
description: clean(result.features[0].attributes.NICE_DESC),
resolution: clean(+parseFloat(result.features[0].attributes.SRC_RES).toFixed(4)),
accuracy: clean(+parseFloat(result.features[0].attributes.SRC_ACC).toFixed(4))
};
// pass through the discrete capture date from metadata
var captureDate = localeDateString(result.SRC_DATE2);
vintage = {
start: captureDate,
end: captureDate,
range: captureDate
};
metadata = {
vintage: vintage,
source: clean(result.NICE_NAME),
description: clean(result.NICE_DESC),
resolution: clean(+parseFloat(result.SRC_RES).toFixed(4)),
accuracy: clean(+parseFloat(result.SRC_ACC).toFixed(4))
};
// append units - meters
if (isFinite(metadata.resolution)) {
metadata.resolution += ' m';
}
if (isFinite(metadata.accuracy)) {
metadata.accuracy += ' m';
}
// append units - meters
if (isFinite(metadata.resolution)) {
metadata.resolution += ' m';
}
if (isFinite(metadata.accuracy)) {
metadata.accuracy += ' m';
}
cache[tileID].metadata = metadata;
if (callback) callback(null, metadata);
})
.catch(function(err) {
delete inflight[tileID];
if (callback) callback(err.message);
});
}
cache[tileID].metadata = metadata;
if (callback) callback(null, metadata);
})
.catch(function(err) {
delete inflight[tileID];
if (callback) callback(err.message);
});
function clean(val) {
+6 -4
View File
@@ -239,7 +239,7 @@ export function rendererTileLayer(context) {
debug
.selectAll('.tile-label-debug-coord')
.html(function(d) { return d[2] + ' / ' + d[0] + ' / ' + d[1]; });
.text(function(d) { return d[2] + ' / ' + d[0] + ' / ' + d[1]; });
debug
.selectAll('.tile-label-debug-vintage')
@@ -247,9 +247,11 @@ export function rendererTileLayer(context) {
var span = d3_select(this);
var center = context.projection.invert(tileCenter(d));
_source.getMetadata(center, d, function(err, result) {
span.html((result && result.vintage && result.vintage.range) ||
t('info_panels.background.vintage') + ': ' + t('info_panels.background.unknown')
);
if (result && result.vintage && result.vintage.range) {
span.text(result.vintage.range);
} else {
span.html(t.html('info_panels.background.vintage') + ': ' + t.html('info_panels.background.unknown'));
}
});
});
}
+10 -10
View File
@@ -276,22 +276,22 @@ export default {
controlsEnter
.append('button')
.on('click.back', step(-1))
.html('◄');
.text('◄');
controlsEnter
.append('button')
.on('click.rotate-ccw', rotate(-90))
.html('⤿');
.text('⤿');
controlsEnter
.append('button')
.on('click.rotate-cw', rotate(90))
.html('⤾');
.text('⤾');
controlsEnter
.append('button')
.on('click.forward', step(1))
.html('►');
.text('►');
wrapEnter
.append('div')
@@ -428,7 +428,7 @@ export default {
var wrap = context.container().select('.photoviewer .kartaview-wrapper');
var imageWrap = wrap.selectAll('.kartaview-image-wrap');
var attribution = wrap.selectAll('.photo-attribution').html('');
var attribution = wrap.selectAll('.photo-attribution').text('');
wrap
.transition()
@@ -455,22 +455,22 @@ export default {
.attr('class', 'captured_by')
.attr('target', '_blank')
.attr('href', 'https://kartaview.org/user/' + encodeURIComponent(d.captured_by))
.html('@' + d.captured_by);
.text('@' + d.captured_by);
attribution
.append('span')
.html('|');
.text('|');
}
if (d.captured_at) {
attribution
.append('span')
.attr('class', 'captured_at')
.html(localeDateString(d.captured_at));
.text(localeDateString(d.captured_at));
attribution
.append('span')
.html('|');
.text('|');
}
attribution
@@ -478,7 +478,7 @@ export default {
.attr('class', 'image-link')
.attr('target', '_blank')
.attr('href', 'https://kartaview.org/details/' + d.sequence_id + '/' + d.sequence_index)
.html('kartaview.org');
.text('kartaview.org');
}
return this;
+23 -12
View File
@@ -458,10 +458,13 @@ function _upgradeTags(tags, loc) {
return changed ? { newTags: newTags, matched: null } : null;
}
// Order the [key,value,name] tuples - test primary before alternate
// Order the [key,value,name] tuples - test primary names before alternate names
const tuples = gatherTuples(tryKVs, tryNames);
let foundPrimary = false;
let bestItem;
for (let i = 0; i < tuples.length; i++) {
// Test [key,value,name] tuples against the NSI matcher until we get a primary match or exhaust all options.
for (let i = 0; (i < tuples.length && !foundPrimary); i++) {
const tuple = tuples[i];
const hits = _nsi.matcher.match(tuple.k, tuple.v, tuple.n, loc); // Attempt to match an item in NSI
@@ -470,14 +473,15 @@ function _upgradeTags(tags, loc) {
// A match may contain multiple results, the first one is likely the best one for this location
// e.g. `['pfk-a54c14', 'kfc-1ff19c', 'kfc-658eea']`
let itemID, item;
for (let j = 0; j < hits.length; j++) {
const hit = hits[j];
itemID = hit.itemID;
const isPrimary = (hits[j].match === 'primary');
const itemID = hit.itemID;
if (_nsi.dissolved[itemID]) continue; // Don't upgrade to a dissolved item
item = _nsi.ids.get(itemID);
const item = _nsi.ids.get(itemID);
if (!item) continue;
const mainTag = item.mainTag; // e.g. `brand:wikidata`
const itemQID = item.tags[mainTag]; // e.g. `brand:wikidata` qid
const notQID = newTags[`not:${mainTag}`]; // e.g. `not:brand:wikidata` qid
@@ -486,18 +490,25 @@ function _upgradeTags(tags, loc) {
(!itemQID || itemQID === notQID) || // No `*:wikidata` or matched a `not:*:wikidata`
(newTags.office && !item.tags.office) // feature may be a corporate office for a brand? - #6416
) {
item = null;
continue; // continue looking
} else {
break; // use `item`
}
// If we get here, the hit is good..
if (!bestItem || isPrimary) {
bestItem = item;
if (isPrimary) {
foundPrimary = true;
}
break; // can ignore the rest of the hits from this match
}
}
}
// Can't use any of these hits, try next tuple..
if (!item) continue;
// At this point we have matched a canonical item and can suggest tag upgrades..
item = JSON.parse(JSON.stringify(item)); // deep copy
// At this point we have matched a canonical item and can suggest tag upgrades..
if (bestItem) {
const itemID = bestItem.id;
const item = JSON.parse(JSON.stringify(bestItem)); // deep copy
const tkv = item.tkv;
const parts = tkv.split('/', 3); // tkv = "tree/key/value"
const k = parts[1];
+1 -1
View File
@@ -589,7 +589,7 @@ export default {
userURL: function(username) {
return urlroot + '/user/' + username;
return urlroot + '/user/' + encodeURIComponent(username);
},
+8 -8
View File
@@ -544,12 +544,12 @@ export default {
controlsEnter
.append('button')
.on('click.back', step(-1))
.html('◄');
.text('◄');
controlsEnter
.append('button')
.on('click.forward', step(1))
.html('►');
.text('►');
// create working canvas for stitching together images
@@ -794,7 +794,7 @@ export default {
label
.append('span')
.html(t.html('streetside.hires'));
.call(t.append('streetside.hires'));
let captureInfo = line1
@@ -810,18 +810,18 @@ export default {
.attr('class', 'captured_by')
.attr('target', '_blank')
.attr('href', 'https://www.microsoft.com/en-us/maps/streetside')
.html('©' + yyyy + ' Microsoft');
.text('©' + yyyy + ' Microsoft');
captureInfo
.append('span')
.html('|');
.text('|');
}
if (d.captured_at) {
captureInfo
.append('span')
.attr('class', 'captured_at')
.html(localeTimestamp(d.captured_at));
.text(localeTimestamp(d.captured_at));
}
// Add image links
@@ -835,7 +835,7 @@ export default {
.attr('target', '_blank')
.attr('href', 'https://www.bing.com/maps?cp=' + d.loc[1] + '~' + d.loc[0] +
'&lvl=17&dir=' + d.ca + '&style=x&v=2&sV=1')
.html(t.html('streetside.view_on_bing'));
.call(t.append('streetside.view_on_bing'));
line2
.append('a')
@@ -843,7 +843,7 @@ export default {
.attr('target', '_blank')
.attr('href', 'https://www.bing.com/maps/privacyreport/streetsideprivacyreport?bubbleid=' +
encodeURIComponent(d.key) + '&focus=photo&lat=' + d.loc[1] + '&lng=' + d.loc[0] + '&z=17')
.html(t.html('streetside.report'));
.call(t.append('streetside.report'));
let bubbleIdQuadKey = d.key.toString(4);
+20
View File
@@ -315,6 +315,21 @@ export function svgData(projection, context, dispatch) {
}
function stringifyGeojsonProperties(feature) {
const properties = feature.properties;
for (const key in properties) {
const property = properties[key];
if (typeof property === 'number' || typeof property === 'boolean' || Array.isArray(property)) {
properties[key] = property.toString();
} else if (property === null) {
properties[key] = 'null';
} else if (typeof property === 'object') {
properties[key] = JSON.stringify(property);
}
}
}
drawData.setFile = function(extension, data) {
_template = null;
_fileList = null;
@@ -332,6 +347,11 @@ export function svgData(projection, context, dispatch) {
case '.geojson':
case '.json':
gj = JSON.parse(data);
if (gj.type === 'FeatureCollection') {
gj.features.forEach(stringifyGeojsonProperties);
} else if (gj.type === 'Feature') {
stringifyGeojsonProperties(gj);
}
break;
}
+1 -1
View File
@@ -49,7 +49,7 @@ export function uiAccount(context) {
logoutLink.append('a')
.attr('class', 'logout')
.attr('href', '#')
.html(t.html('logout'))
.call(t.append('logout'))
.on('click.logout', function(d3_event) {
d3_event.preventDefault();
osm.logout();
+2 -2
View File
@@ -56,7 +56,7 @@ export function uiAttribution(context) {
attribution
.append('span')
.attr('class', 'attribution-text')
.html(terms_text);
.text(terms_text);
})
.merge(attributions);
@@ -76,7 +76,7 @@ export function uiAttribution(context) {
.merge(copyright);
copyright
.html(String);
.text(String);
}
+1 -1
View File
@@ -107,7 +107,7 @@ export function uiChangesetEditor(context) {
.call(svgIcon('#iD-icon-alert', 'inline'))
.attr('href', t('commit.google_warning_link'))
.append('span')
.html(t.html('commit.google_warning'));
.call(t.append('commit.google_warning'));
commentEnter
.transition()
+7 -7
View File
@@ -221,7 +221,7 @@ export function uiCommit(context) {
headerTitle
.append('div')
.append('h2')
.html(t.html('commit.title'));
.call(t.append('commit.title'));
headerTitle
.append('button')
@@ -280,7 +280,7 @@ export function uiCommit(context) {
prose = prose.enter()
.append('p')
.attr('class', 'commit-info')
.html(t.html('commit.upload_explanation'))
.call(t.append('commit.upload_explanation'))
.merge(prose);
// always check if this has changed, but only update prose.html()
@@ -303,12 +303,12 @@ export function uiCommit(context) {
userLink
.append('a')
.attr('class', 'user-info')
.html(user.display_name)
.text(user.display_name)
.attr('href', osm.userURL(user.display_name))
.attr('target', '_blank');
prose
.html(t.html('commit.upload_explanation_with_user', { user: userLink.html() }));
.html(t.html('commit.upload_explanation_with_user', { user: { html: userLink.html() } }));
});
@@ -339,7 +339,7 @@ export function uiCommit(context) {
labelEnter
.append('span')
.html(t.html('commit.request_review'));
.call(t.append('commit.request_review'));
// Update
requestReview = requestReview
@@ -364,7 +364,7 @@ export function uiCommit(context) {
.attr('class', 'secondary-action button cancel-button')
.append('span')
.attr('class', 'label')
.html(t.html('commit.cancel'));
.call(t.append('commit.cancel'));
var uploadButton = buttonEnter
.append('button')
@@ -372,7 +372,7 @@ export function uiCommit(context) {
uploadButton.append('span')
.attr('class', 'label')
.html(t.html('commit.save'));
.call(t.append('commit.save'));
var uploadBlockerTooltipText = getUploadBlockerMessage();
+1 -1
View File
@@ -27,7 +27,7 @@ export function uiConfirm(selection) {
.on('click.confirm', function() {
modalSelection.remove();
})
.html(t.html('confirm.okay'))
.call(t.append('confirm.okay'))
.node()
.focus();
+9 -9
View File
@@ -66,7 +66,7 @@ export function uiConflicts(context) {
headerEnter
.append('h2')
.html(t.html('save.conflict.header'));
.call(t.append('save.conflict.header'));
var bodyEnter = selection.selectAll('.body')
.data([0])
@@ -77,7 +77,7 @@ export function uiConflicts(context) {
var conflictsHelpEnter = bodyEnter
.append('div')
.attr('class', 'conflicts-help')
.html(t.html('save.conflict.help'));
.call(t.append('save.conflict.help'));
// Download changes link
@@ -110,7 +110,7 @@ export function uiConflicts(context) {
linkEnter
.call(svgIcon('#iD-icon-load', 'inline'))
.append('span')
.html(t.html('save.conflict.download_changes'));
.call(t.append('save.conflict.download_changes'));
bodyEnter
@@ -123,7 +123,7 @@ export function uiConflicts(context) {
.attr('class', 'conflicts-done')
.attr('opacity', 0)
.style('display', 'none')
.html(t.html('save.conflict.done'));
.call(t.append('save.conflict.done'));
var buttonsEnter = bodyEnter
.append('div')
@@ -133,13 +133,13 @@ export function uiConflicts(context) {
.append('button')
.attr('disabled', _conflictList.length > 1)
.attr('class', 'action conflicts-button col6')
.html(t.html('save.title'))
.call(t.append('save.title'))
.on('click.try_again', tryAgain);
buttonsEnter
.append('button')
.attr('class', 'secondary-action conflicts-button col6')
.html(t.html('confirm.cancel'))
.call(t.append('confirm.cancel'))
.on('click.cancel', cancel);
}
@@ -177,13 +177,13 @@ export function uiConflicts(context) {
conflictEnter
.append('h4')
.attr('class', 'conflict-count')
.html(t.html('save.conflict.count', { num: index + 1, total: _conflictList.length }));
.call(t.append('save.conflict.count', { num: index + 1, total: _conflictList.length }));
conflictEnter
.append('a')
.attr('class', 'conflict-description')
.attr('href', '#')
.html(function(d) { return d.name; })
.text(function(d) { return d.name; })
.on('click', function(d3_event, d) {
d3_event.preventDefault();
zoomToEntity(d.id);
@@ -265,7 +265,7 @@ export function uiConflicts(context) {
labelEnter
.append('span')
.html(function(d) { return d.text; });
.text(function(d) { return d.text; });
// update
choicesEnter
+4 -4
View File
@@ -39,7 +39,7 @@ export function uiContributors(context) {
.attr('class', 'user-link')
.attr('href', function(d) { return osm.userURL(d); })
.attr('target', '_blank')
.html(String);
.text(String);
if (u.length > limit) {
var count = d3_select(document.createElement('span'));
@@ -51,14 +51,14 @@ export function uiContributors(context) {
.attr('href', function() {
return osm.changesetsURL(context.map().center(), context.map().zoom());
})
.html(othersNum);
.text(othersNum);
wrap.append('span')
.html(t.html('contributors.truncated_list', { n: othersNum, users: userList.html(), count: count.html() }));
.html(t.html('contributors.truncated_list', { n: othersNum, users: { html: userList.html() }, count: { html: count.html() } }));
} else {
wrap.append('span')
.html(t.html('contributors.list', { users: userList.html() }));
.html(t.html('contributors.list', { users: { html: userList.html() } }));
}
if (!u.length) {
+1 -1
View File
@@ -34,7 +34,7 @@ export function uiDataEditor(context) {
headerEnter
.append('h2')
.html(t.html('map_data.title'));
.call(t.append('map_data.title'));
var body = selection.selectAll('.body')
+1 -1
View File
@@ -32,7 +32,7 @@ export function uiDataHeader() {
headerEnter
.append('div')
.attr('class', 'data-header-label')
.html(t.html('map_data.layers.custom.title'));
.call(t.append('map_data.layers.custom.title'));
}
+1 -1
View File
@@ -114,7 +114,7 @@ export function uiEditMenu(context) {
.call(tooltip)
.append('div')
.attr('class', 'icon-wrap')
.call(svgIcon('#iD-operation-' + d.id, 'operation'));
.call(svgIcon(d.icon && d.icon() || '#iD-operation-' + d.id, 'operation'));
});
if (showLabels) {
+4 -1
View File
@@ -165,7 +165,10 @@ export function uiEntityEditor(context) {
for (var k in changed) {
if (!k) continue;
var v = changed[k];
if (v !== undefined || tags.hasOwnProperty(k)) {
if (typeof v === 'object') {
// a "key only" tag change
tags[k] = tags[v.oldKey];
} else if (v !== undefined || tags.hasOwnProperty(k)) {
tags[k] = v;
}
}
+2 -2
View File
@@ -9,7 +9,7 @@ export function uiFeatureInfo(context) {
var hiddenList = features.hidden().map(function(k) {
if (stats[k]) {
count += stats[k];
return t('inspector.title_count', { title: t.html('feature.' + k + '.description'), count: stats[k] });
return t.html('inspector.title_count', { title: { html: t.html('feature.' + k + '.description') }, count: stats[k] });
}
return null;
}).filter(Boolean);
@@ -26,7 +26,7 @@ export function uiFeatureInfo(context) {
selection.append('a')
.attr('class', 'chip')
.attr('href', '#')
.html(t.html('feature_info.hidden_warning', { count: count }))
.call(t.append('feature_info.hidden_warning', { count: count }))
.call(tooltipBehavior)
.on('click', function(d3_event) {
tooltipBehavior.hide();
+6 -5
View File
@@ -34,7 +34,7 @@ export function uiFeatureList(context) {
header
.append('h2')
.html(t.html('inspector.feature_list'));
.call(t.append('inspector.feature_list'));
var searchWrap = selection
.append('div')
@@ -255,7 +255,8 @@ export function uiFeatureList(context) {
.attr('class', 'entity-name');
list.selectAll('.no-results-item .entity-name')
.html(t.html('geocoder.no_results_worldwide'));
.html('')
.call(t.append('geocoder.no_results_worldwide'));
if (services.geocoder) {
list.selectAll('.geocode-item')
@@ -268,7 +269,7 @@ export function uiFeatureList(context) {
.attr('class', 'label')
.append('span')
.attr('class', 'entity-name')
.html(t.html('geocoder.search'));
.call(t.append('geocoder.search'));
}
list.selectAll('.no-results-item')
@@ -304,12 +305,12 @@ export function uiFeatureList(context) {
label
.append('span')
.attr('class', 'entity-type')
.html(function(d) { return d.type; });
.text(function(d) { return d.type; });
label
.append('span')
.attr('class', 'entity-name')
.html(function(d) { return d.name; });
.text(function(d) { return d.name; });
enter
.style('opacity', 0)
+10 -10
View File
@@ -54,15 +54,15 @@ export function uiFieldHelp(context, fieldName) {
var fieldHelpHeadings = {};
var replacements = {
distField: t.html('restriction.controls.distance'),
viaField: t.html('restriction.controls.via'),
fromShadow: icon('#iD-turn-shadow', 'inline shadow from'),
allowShadow: icon('#iD-turn-shadow', 'inline shadow allow'),
restrictShadow: icon('#iD-turn-shadow', 'inline shadow restrict'),
onlyShadow: icon('#iD-turn-shadow', 'inline shadow only'),
allowTurn: icon('#iD-turn-yes', 'inline turn'),
restrictTurn: icon('#iD-turn-no', 'inline turn'),
onlyTurn: icon('#iD-turn-only', 'inline turn')
distField: { html: t.html('restriction.controls.distance') },
viaField: { html: t.html('restriction.controls.via') },
fromShadow: { html: icon('#iD-turn-shadow', 'inline shadow from') },
allowShadow: { html: icon('#iD-turn-shadow', 'inline shadow allow') },
restrictShadow: { html: icon('#iD-turn-shadow', 'inline shadow restrict') },
onlyShadow: { html: icon('#iD-turn-shadow', 'inline shadow only') },
allowTurn: { html: icon('#iD-turn-yes', 'inline turn') },
restrictTurn: { html: icon('#iD-turn-no', 'inline turn') },
onlyTurn: { html: icon('#iD-turn-only', 'inline turn') }
};
@@ -196,7 +196,7 @@ export function uiFieldHelp(context, fieldName) {
titleEnter
.append('h2')
.attr('class', ((localizer.textDirection() === 'rtl') ? 'fr' : 'fl'))
.html(t.html('help.field.' + fieldName + '.title'));
.call(t.append('help.field.' + fieldName + '.title'));
titleEnter
.append('button')
+1 -1
View File
@@ -288,7 +288,7 @@ export function uiFieldAddress(field, context) {
})
.attr('title', function(subfield) {
var val = tags[field.key + ':' + subfield.id];
return val && Array.isArray(val) && val.filter(Boolean).join('\n');
return (val && Array.isArray(val)) ? val.filter(Boolean).join('\n') : undefined;
})
.classed('mixed', function(subfield) {
return Array.isArray(tags[field.key + ':' + subfield.id]);
+2 -1
View File
@@ -83,7 +83,8 @@ export function uiFieldCheck(field, context) {
var icon = pseudoDirection ? '#iD-icon-forward' : '#iD-icon-backward';
selection.selectAll('.reverser-span')
.html(t.html('inspector.check.reverser'))
.html('')
.call(t.append('inspector.check.reverser'))
.call(svgIcon(icon, 'inline'));
return selection;
+2 -2
View File
@@ -527,13 +527,13 @@ export function uiFieldCombo(field, context) {
}
chips.select('span')
.html(function(d) { return d.value; });
.text(function(d) { return d.value; });
chips.select('a')
.attr('href', '#')
.on('click', removeMultikey)
.attr('class', 'remove')
.html('×');
.text('×');
} else {
var isMixed = Array.isArray(tags[field.key]);
+72 -4
View File
@@ -1,5 +1,6 @@
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { select as d3_select } from 'd3-selection';
import _debounce from 'lodash-es/debounce';
import * as countryCoder from '@ideditor/country-coder';
import { presetManager } from '../../presets';
@@ -21,6 +22,7 @@ export function uiFieldText(field, context) {
var dispatch = d3_dispatch('change');
var input = d3_select(null);
var outlinkButton = d3_select(null);
var wrap = d3_select(null);
var _entityIDs = [];
var _tags;
var _phoneFormats = {};
@@ -62,7 +64,7 @@ export function uiFieldText(field, context) {
calcLocked();
var isLocked = field.locked();
var wrap = selection.selectAll('.form-field-input-wrap')
wrap = selection.selectAll('.form-field-input-wrap')
.data([0]);
wrap = wrap.enter()
@@ -171,9 +173,67 @@ export function uiFieldText(field, context) {
if (value) window.open(value, '_blank');
})
.merge(outlinkButton);
} else if (field.key.split(':').includes('colour')) {
input.attr('type', 'text');
updateColourPreview();
}
}
function isColourValid(colour) {
if (!colour.match(/^(#([0-9a-fA-F]{3}){1,2}|\w+)$/)) {
// OSM only supports hex or named colors
return false;
} else if (!CSS.supports('color', colour) || ['unset', 'inherit', 'initial', 'revert'].includes(colour)) {
// see https://stackoverflow.com/a/68217760/1627467
return false;
}
return true;
}
function updateColourPreview() {
wrap.selectAll('.colour-preview')
.remove();
const colour = utilGetSetValue(input);
if (!isColourValid(colour) && colour !== '') return;
var colourSelector = wrap.selectAll('.colour-selector')
.data([0]);
outlinkButton = wrap.selectAll('.colour-preview')
.data([colour]);
colourSelector
.enter()
.append('input')
.attr('type', 'color')
.attr('class', 'form-field-button colour-selector')
.attr('value', colour)
.on('input', _debounce(function(d3_event) {
d3_event.preventDefault();
var colour = this.value;
if (!isColourValid(colour)) return;
utilGetSetValue(input, this.value);
change()();
updateColourPreview();
}, 100));
outlinkButton = outlinkButton
.enter()
.append('div')
.attr('class', 'form-field-button colour-preview')
.append('div')
.style('background-color', d => d)
.attr('class', 'colour-box');
if (colour === '') {
outlinkButton = outlinkButton
.call(svgIcon('#iD-icon-edit'));
}
outlinkButton
.on('click', () => wrap.select('.colour-selector').node().click())
.merge(outlinkButton);
}
function updatePhonePlaceholder() {
if (input.empty() || !Object.keys(_phoneFormats).length) return;
@@ -186,11 +246,17 @@ export function uiFieldText(field, context) {
function validIdentifierValueForLink() {
const value = utilGetSetValue(input).trim().split(';')[0];
const value = utilGetSetValue(input).trim();
if (field.type === 'url' && value) return value;
if (field.type === 'url' && value) {
try {
return (new URL(value)).href;
} catch (e) {
return null;
}
}
if (field.type === 'identifier' && field.pattern) {
return value && value.match(new RegExp(field.pattern));
return value && value.match(new RegExp(field.pattern))[0];
}
return null;
}
@@ -251,6 +317,8 @@ export function uiFieldText(field, context) {
.attr('placeholder', isMixed ? t('inspector.multiple_values') : (field.placeholder() || t('inspector.unknown')))
.classed('mixed', isMixed);
if (field.key.split(':').includes('colour')) updateColourPreview();
if (outlinkButton && !outlinkButton.empty()) {
var disabled = !validIdentifierValueForLink();
outlinkButton.classed('disabled', disabled);
+3 -3
View File
@@ -77,7 +77,7 @@ export function uiFieldLanes(field, context) {
.append('text')
.attr('y', 40)
.attr('x', 14)
.html('▲');
.text('▲');
enter
.append('g')
@@ -85,7 +85,7 @@ export function uiFieldLanes(field, context) {
.append('text')
.attr('y', 40)
.attr('x', 14)
.html('▲▼');
.text('▲▼');
enter
.append('g')
@@ -93,7 +93,7 @@ export function uiFieldLanes(field, context) {
.append('text')
.attr('y', 40)
.attr('x', 14)
.html('▼');
.text('▼');
lane = lane
+1 -1
View File
@@ -374,7 +374,7 @@ export function uiFieldLocalized(field, context) {
text
.append('span')
.attr('class', 'label-textvalue')
.html(t.html('translate.localized_translation_label'));
.call(t.append('translate.localized_translation_label'));
text
.append('span')
+4 -4
View File
@@ -129,7 +129,7 @@ export function uiFieldRadio(field, context) {
.append('span')
.attr('class', 'label structure-label-type')
.attr('for', 'preset-input-' + selected)
.html(t.html('inspector.radio.structure.type'));
.call(t.append('inspector.radio.structure.type'));
typeEnter
.append('div')
@@ -174,7 +174,7 @@ export function uiFieldRadio(field, context) {
.append('span')
.attr('class', 'label structure-label-layer')
.attr('for', 'preset-input-layer')
.html(t.html('inspector.radio.structure.layer'));
.call(t.append('inspector.radio.structure.layer'));
layerEnter
.append('div')
@@ -302,9 +302,9 @@ export function uiFieldRadio(field, context) {
var selection = radios.filter(function() { return this.checked; });
if (selection.empty()) {
placeholder.html(t.html('inspector.none'));
placeholder.call(t.append('inspector.none'));
} else {
placeholder.html(selection.attr('value'));
placeholder.text(selection.attr('value'));
_oldType[selection.datum()] = tags[selection.datum()];
}
+27 -20
View File
@@ -124,7 +124,7 @@ export function uiFieldRestrictions(field, context) {
distControlEnter
.append('span')
.attr('class', 'restriction-control-label restriction-distance-label')
.html(t.html('restriction.controls.distance') + ':');
.call(t.append('restriction.controls.distance', { suffix: ':' }));
distControlEnter
.append('input')
@@ -151,7 +151,7 @@ export function uiFieldRestrictions(field, context) {
});
selection.selectAll('.restriction-distance-text')
.html(displayMaxDistance(_maxDistance));
.call(displayMaxDistance(_maxDistance));
var viaControl = selection.selectAll('.restriction-via-way')
@@ -167,7 +167,7 @@ export function uiFieldRestrictions(field, context) {
viaControlEnter
.append('span')
.attr('class', 'restriction-control-label restriction-via-way-label')
.html(t.html('restriction.controls.via') + ':');
.call(t.append('restriction.controls.via', { suffix: ':' }));
viaControlEnter
.append('input')
@@ -193,7 +193,7 @@ export function uiFieldRestrictions(field, context) {
});
selection.selectAll('.restriction-via-way-text')
.html(displayMaxVia(_maxViaWay));
.call(displayMaxVia(_maxViaWay));
}
@@ -463,7 +463,7 @@ export function uiFieldRestrictions(field, context) {
var placeholders = {};
['from', 'via', 'to'].forEach(function(k) {
placeholders[k] = '<span class="qualifier">' + t('restriction.help.' + k) + '</span>';
placeholders[k] = { html: '<span class="qualifier">' + t('restriction.help.' + k) + '</span>' };
});
var entity = datum && datum.properties && datum.properties.entity;
@@ -553,7 +553,7 @@ export function uiFieldRestrictions(field, context) {
if (!indirect) {
help
.append('div') // Click for "No Right Turn"
.html(t.html('restriction.help.toggle', { turn: nextText.trim() }));
.html(t.html('restriction.help.toggle', { turn: { html: nextText.trim() } }));
}
highlightPathsFrom(null);
@@ -589,26 +589,33 @@ export function uiFieldRestrictions(field, context) {
function displayMaxDistance(maxDist) {
var isImperial = !localizer.usesMetric();
var opts;
return selection => {
var isImperial = !localizer.usesMetric();
var opts;
if (isImperial) {
var distToFeet = { // imprecise conversion for prettier display
20: 70, 25: 85, 30: 100, 35: 115, 40: 130, 45: 145, 50: 160
}[maxDist];
opts = { distance: t('units.feet', { quantity: distToFeet }) };
} else {
opts = { distance: t('units.meters', { quantity: maxDist }) };
}
if (isImperial) {
var distToFeet = { // imprecise conversion for prettier display
20: 70, 25: 85, 30: 100, 35: 115, 40: 130, 45: 145, 50: 160
}[maxDist];
opts = { distance: t('units.feet', { quantity: distToFeet }) };
} else {
opts = { distance: t('units.meters', { quantity: maxDist }) };
}
return t.html('restriction.controls.distance_up_to', opts);
return selection
.html('')
.call(t.append('restriction.controls.distance_up_to', opts));
};
}
function displayMaxVia(maxVia) {
return maxVia === 0 ? t.html('restriction.controls.via_node_only')
: maxVia === 1 ? t.html('restriction.controls.via_up_to_one')
: t.html('restriction.controls.via_up_to_two');
return selection => {
selection = selection.html('');
return maxVia === 0 ? selection.call(t.append('restriction.controls.via_node_only'))
: maxVia === 1 ? selection.call(t.append('restriction.controls.via_up_to_one'))
: selection.call(t.append('restriction.controls.via_up_to_two'));
};
}
+1 -1
View File
@@ -84,7 +84,7 @@ export function uiFormFields(context) {
moreEnter
.append('span')
.html(t.html('inspector.add_fields'));
.call(t.append('inspector.add_fields'));
more = moreEnter
.merge(more);
+2 -2
View File
@@ -55,7 +55,7 @@ export function uiImproveOsmComments() {
.attr('target', '_blank');
}
selection
.html(d => d.username);
.text(d => d.username);
});
metadataEnter
@@ -67,7 +67,7 @@ export function uiImproveOsmComments() {
.append('div')
.attr('class', 'comment-text')
.append('p')
.html(d => d.text);
.text(d => d.text);
})
.catch(err => {
console.log(err); // eslint-disable-line no-console
+2 -2
View File
@@ -42,12 +42,12 @@ export function uiImproveOsmDetails(context) {
descriptionEnter
.append('h4')
.html(t.html('QA.keepRight.detail_description'));
.call(t.append('QA.keepRight.detail_description'));
descriptionEnter
.append('div')
.attr('class', 'qa-details-description-text')
.html(issueDetail);
.text(issueDetail);
// If there are entity links in the error message..
let relatedEntities = [];
+3 -3
View File
@@ -37,7 +37,7 @@ export function uiImproveOsmEditor(context) {
headerEnter
.append('h2')
.html(t.html('QA.improveOSM.title'));
.call(t.append('QA.improveOSM.title'));
let body = selection.selectAll('.body')
.data([0]);
@@ -81,7 +81,7 @@ export function uiImproveOsmEditor(context) {
saveSectionEnter
.append('h4')
.attr('class', '.qa-save-header')
.html(t.html('note.newComment'));
.call(t.append('note.newComment'));
saveSectionEnter
.append('textarea')
@@ -136,7 +136,7 @@ export function uiImproveOsmEditor(context) {
buttonEnter
.append('button')
.attr('class', 'button comment-button action')
.html(t.html('QA.keepRight.save_comment'));
.call(t.append('QA.keepRight.save_comment'));
buttonEnter
.append('button')
+1 -1
View File
@@ -62,7 +62,7 @@ export function uiImproveOsmHeader() {
headerEnter
.append('div')
.attr('class', 'qa-header-label')
.html(issueTitle);
.text(issueTitle);
}
improveOsmHeader.issue = function(val) {
+3
View File
@@ -146,6 +146,9 @@ export function helpHtml(id, replacements) {
help: t.html('help.title'),
ok: t.html('intro.ok')
};
for (var key in helpStringReplacements) {
helpStringReplacements[key] = { html: helpStringReplacements[key] };
}
}
var reps;
+8 -8
View File
@@ -355,7 +355,7 @@ export function uiIntroNavigation(context, reveal) {
var href = d3_select(selector).attr('href') || '#iD-icon-close';
reveal('.entity-editor-pane',
helpHtml('intro.navigation.close_townhall', { button: icon(href, 'inline') })
helpHtml('intro.navigation.close_townhall', { button: { html: icon(href, 'inline') } })
);
context.on('exit.intro', function() {
@@ -368,7 +368,7 @@ export function uiIntroNavigation(context, reveal) {
var href = d3_select(selector).attr('href') || '#iD-icon-close';
reveal('.entity-editor-pane',
helpHtml('intro.navigation.close_townhall', { button: icon(href, 'inline') }),
helpHtml('intro.navigation.close_townhall', { button: { html: icon(href, 'inline') } }),
{ duration: 0 }
);
});
@@ -492,9 +492,9 @@ export function uiIntroNavigation(context, reveal) {
reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' +
helpHtml('intro.navigation.editor_street', {
button: icon(href, 'inline'),
field1: onewayField.label(),
field2: maxspeedField.label()
button: { html: icon(href, 'inline') },
field1: { html: onewayField.label() },
field2: { html: maxspeedField.label() }
}));
context.on('exit.intro', function() {
@@ -508,9 +508,9 @@ export function uiIntroNavigation(context, reveal) {
reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' +
helpHtml('intro.navigation.editor_street', {
button: icon(href, 'inline'),
field1: onewayField.label(),
field2: maxspeedField.label()
button: { html: icon(href, 'inline') },
field1: { html: onewayField.label() },
field2: { html: maxspeedField.label() }
}), { duration: 0 }
);
});
+1 -1
View File
@@ -72,7 +72,7 @@ export function uiIntroStartEditing(context, reveal) {
startbutton
.append('h2')
.html(t.html('intro.startediting.start'));
.call(t.append('intro.startediting.start'));
dispatch.call('startEditing');
}
+1 -1
View File
@@ -83,7 +83,7 @@ export function uiIssuesInfo(context) {
enter.merge(chips)
.selectAll('span.count')
.html(function(d) {
.text(function(d) {
return d.count.toString();
});
}
+1 -1
View File
@@ -47,7 +47,7 @@ export function uiKeepRightDetails(context) {
descriptionEnter
.append('h4')
.html(t.html('QA.keepRight.detail_description'));
.call(t.append('QA.keepRight.detail_description'));
descriptionEnter
.append('div')
+3 -3
View File
@@ -36,7 +36,7 @@ export function uiKeepRightEditor(context) {
headerEnter
.append('h2')
.html(t.html('QA.keepRight.title'));
.call(t.append('QA.keepRight.title'));
let body = selection.selectAll('.body')
@@ -91,7 +91,7 @@ export function uiKeepRightEditor(context) {
saveSectionEnter
.append('h4')
.attr('class', '.qa-save-header')
.html(t.html('QA.keepRight.comment'));
.call(t.append('QA.keepRight.comment'));
saveSectionEnter
.append('textarea')
@@ -147,7 +147,7 @@ export function uiKeepRightEditor(context) {
buttonEnter
.append('button')
.attr('class', 'button comment-button action')
.html(t.html('QA.keepRight.save_comment'));
.call(t.append('QA.keepRight.save_comment'));
buttonEnter
.append('button')
+6 -3
View File
@@ -53,15 +53,18 @@ export function uiNoteComments() {
.attr('href', osm.userURL(d.user))
.attr('target', '_blank');
}
selection
.html(function(d) { return d.user || t.html('note.anonymous'); });
if (d.user) {
selection.text(d.user);
} else {
selection.call(t.append('note.anonymous'));
}
});
metadataEnter
.append('div')
.attr('class', 'comment-date')
.html(function(d) {
return t('note.status.' + d.action, { when: localeDateString(d.date) });
return t.html('note.status.' + d.action, { when: localeDateString(d.date) });
});
mainEnter
+11 -11
View File
@@ -54,7 +54,7 @@ export function uiNoteEditor(context) {
headerEnter
.append('h2')
.html(t.html('note.title'));
.call(t.append('note.title'));
var body = selection.selectAll('.body')
@@ -149,7 +149,7 @@ export function uiNoteEditor(context) {
.append('h4')
.attr('class', '.note-save-header')
.html(function() {
return _note.isNew() ? t('note.newDescription') : t('note.newComment');
return _note.isNew() ? t.html('note.newDescription') : t.html('note.newComment');
});
var commentTextarea = noteSaveEnter
@@ -257,14 +257,14 @@ export function uiNoteEditor(context) {
authEnter
.append('span')
.html(t.html('note.login'));
.call(t.append('note.login'));
authEnter
.append('a')
.attr('target', '_blank')
.call(svgIcon('#iD-icon-out-link', 'inline'))
.append('span')
.html(t.html('login'))
.call(t.append('login'))
.on('click.note-login', function(d3_event) {
d3_event.preventDefault();
osm.authenticate();
@@ -285,7 +285,7 @@ export function uiNoteEditor(context) {
prose = prose.enter()
.append('p')
.attr('class', 'note-save-prose')
.html(t.html('note.upload_explanation'))
.call(t.append('note.upload_explanation'))
.merge(prose);
osm.userDetails(function(err, user) {
@@ -303,12 +303,12 @@ export function uiNoteEditor(context) {
userLink
.append('a')
.attr('class', 'user-info')
.html(user.display_name)
.text(user.display_name)
.attr('href', osm.userURL(user.display_name))
.attr('target', '_blank');
prose
.html(t.html('note.upload_explanation_with_user', { user: userLink.html() }));
.html(t.html('note.upload_explanation_with_user', { user: { html: userLink.html() } }));
});
}
@@ -334,12 +334,12 @@ export function uiNoteEditor(context) {
buttonEnter
.append('button')
.attr('class', 'button cancel-button secondary-action')
.html(t.html('confirm.cancel'));
.call(t.append('confirm.cancel'));
buttonEnter
.append('button')
.attr('class', 'button save-button action')
.html(t.html('note.save'));
.call(t.append('note.save'));
} else {
buttonEnter
@@ -349,7 +349,7 @@ export function uiNoteEditor(context) {
buttonEnter
.append('button')
.attr('class', 'button comment-button action')
.html(t.html('note.comment'));
.call(t.append('note.comment'));
}
@@ -369,7 +369,7 @@ export function uiNoteEditor(context) {
.html(function(d) {
var action = (d.status === 'open' ? 'close' : 'open');
var andComment = (d.newComment ? '_comment' : '');
return t('note.' + action + andComment);
return t.html('note.' + action + andComment);
})
.on('click.status', clickStatus);
+3 -3
View File
@@ -50,9 +50,9 @@ export function uiNoteHeader() {
.append('div')
.attr('class', 'note-header-label')
.html(function(d) {
if (_note.isNew()) { return t('note.new'); }
return t('note.note') + ' ' + d.id + ' ' +
(d.status === 'closed' ? t('note.closed') : '');
if (_note.isNew()) { return t.html('note.new'); }
return t.html('note.note') + ' ' + d.id + ' ' +
(d.status === 'closed' ? t.html('note.closed') : '');
});
}
+1 -1
View File
@@ -30,7 +30,7 @@ export function uiNoteReport() {
linkEnter
.append('span')
.html(t.html('note.report'));
.call(t.append('note.report'));
}
+1 -1
View File
@@ -26,7 +26,7 @@ export function uiNotice(context) {
.call(svgIcon('#iD-icon-plus', 'pre-text'))
.append('span')
.attr('class', 'label')
.html(t.html('zoom_in_edit'));
.call(t.append('zoom_in_edit'));
function disableTooHigh() {
+6 -6
View File
@@ -44,7 +44,7 @@ export function uiOsmoseDetails(context) {
div
.append('h4')
.html(t.html('QA.keepRight.detail_description'));
.call(t.append('QA.keepRight.detail_description'));
div
.append('p')
@@ -72,7 +72,7 @@ export function uiOsmoseDetails(context) {
div
.append('h4')
.html(t.html('QA.osmose.fix_title'));
.call(t.append('QA.osmose.fix_title'));
div
.append('p')
@@ -90,7 +90,7 @@ export function uiOsmoseDetails(context) {
div
.append('h4')
.html(t.html('QA.osmose.trap_title'));
.call(t.append('QA.osmose.trap_title'));
div
.append('p')
@@ -117,7 +117,7 @@ export function uiOsmoseDetails(context) {
if (d.detail) {
detailsDiv
.append('h4')
.html(t.html('QA.osmose.detail_title'));
.call(t.append('QA.osmose.detail_title'));
detailsDiv
.append('p')
@@ -130,7 +130,7 @@ export function uiOsmoseDetails(context) {
// Create list of linked issue elements
elemsDiv
.append('h4')
.html(t.html('QA.osmose.elems_title'));
.call(t.append('QA.osmose.elems_title'));
elemsDiv
.append('ul').selectAll('li')
@@ -140,7 +140,7 @@ export function uiOsmoseDetails(context) {
.append('a')
.attr('href', '#')
.attr('class', 'error_entity_link')
.html(d => d)
.text(d => d)
.each(function() {
const link = d3_select(this);
const entityID = this.textContent;
+3 -3
View File
@@ -36,7 +36,7 @@ export function uiOsmoseEditor(context) {
headerEnter
.append('h2')
.html(t.html('QA.osmose.title'));
.call(t.append('QA.osmose.title'));
let body = selection.selectAll('.body')
.data([0]);
@@ -118,7 +118,7 @@ export function uiOsmoseEditor(context) {
.merge(buttonEnter);
buttonSection.select('.close-button')
.html(t.html('QA.keepRight.close'))
.call(t.append('QA.keepRight.close'))
.on('click.close', function(d3_event, d) {
this.blur(); // avoid keeping focus on the button - #4641
const qaService = services.osmose;
@@ -129,7 +129,7 @@ export function uiOsmoseEditor(context) {
});
buttonSection.select('.ignore-button')
.html(t.html('QA.keepRight.ignore'))
.call(t.append('QA.keepRight.ignore'))
.on('click.ignore', function(d3_event, d) {
this.blur(); // avoid keeping focus on the button - #4641
const qaService = services.osmose;
+1 -1
View File
@@ -65,7 +65,7 @@ export function uiOsmoseHeader() {
headerEnter
.append('div')
.attr('class', 'qa-header-label')
.html(issueTitle);
.text(issueTitle);
}
osmoseHeader.issue = function(val) {
+7 -7
View File
@@ -43,10 +43,10 @@ export function uiPanelBackground(context) {
.append('li')
.attr('class', 'background-info-list-' + k)
.classed('hide', !_metadata[k])
.html(t.html('info_panels.background.' + k) + ':')
.call(t.append('info_panels.background.' + k, { suffix: ':' }))
.append('span')
.attr('class', 'background-info-span-' + k)
.html(_metadata[k]);
.text(_metadata[k]);
});
debouncedGetMetadata(selection);
@@ -55,7 +55,7 @@ export function uiPanelBackground(context) {
selection
.append('a')
.html(t.html('info_panels.background.' + toggleTiles))
.call(t.append('info_panels.background.' + toggleTiles))
.attr('href', '#')
.attr('class', 'button button-toggle-tiles')
.on('click', function(d3_event) {
@@ -71,7 +71,7 @@ export function uiPanelBackground(context) {
var toggleVintage = showsVintage ? 'hide_vintage' : 'show_vintage';
selection
.append('a')
.html(t.html('info_panels.background.' + toggleVintage))
.call(t.append('info_panels.background.' + toggleVintage))
.attr('href', '#')
.attr('class', 'button button-toggle-vintage')
.on('click', function(d3_event) {
@@ -110,7 +110,7 @@ export function uiPanelBackground(context) {
selection.selectAll('.background-info-list-zoom')
.classed('hide', false)
.selectAll('.background-info-span-zoom')
.html(_metadata.zoom);
.text(_metadata.zoom);
if (!d || !d.length >= 3) return;
@@ -123,7 +123,7 @@ export function uiPanelBackground(context) {
selection.selectAll('.background-info-list-vintage')
.classed('hide', false)
.selectAll('.background-info-span-vintage')
.html(_metadata.vintage);
.text(_metadata.vintage);
// update other _metadata
_metadataKeys.forEach(function(k) {
@@ -133,7 +133,7 @@ export function uiPanelBackground(context) {
selection.selectAll('.background-info-list-' + k)
.classed('hide', !val)
.selectAll('.background-info-span-' + k)
.html(val);
.text(val);
});
});
}
+37 -32
View File
@@ -21,14 +21,14 @@ export function uiPanelHistory(context) {
if (!userName) {
selection
.append('span')
.html(t.html('info_panels.history.unknown'));
.call(t.append('info_panels.history.unknown'));
return;
}
selection
.append('span')
.attr('class', 'user-name')
.html(userName);
.text(userName);
var links = selection
.append('div')
@@ -40,7 +40,7 @@ export function uiPanelHistory(context) {
.attr('class', 'user-osm-link')
.attr('href', osm.userURL(userName))
.attr('target', '_blank')
.html('OSM');
.call(t.append('info_panels.history.profile_link'));
}
links
@@ -49,7 +49,7 @@ export function uiPanelHistory(context) {
.attr('href', 'https://hdyc.neis-one.org/?' + userName)
.attr('target', '_blank')
.attr('tabindex', -1)
.html('HDYC');
.text('HDYC');
}
@@ -57,14 +57,14 @@ export function uiPanelHistory(context) {
if (!changeset) {
selection
.append('span')
.html(t.html('info_panels.history.unknown'));
.call(t.append('info_panels.history.unknown'));
return;
}
selection
.append('span')
.attr('class', 'changeset-id')
.html(changeset);
.text(changeset);
var links = selection
.append('div')
@@ -76,7 +76,7 @@ export function uiPanelHistory(context) {
.attr('class', 'changeset-osm-link')
.attr('href', osm.changesetURL(changeset))
.attr('target', '_blank')
.html('OSM');
.call(t.append('info_panels.history.changeset_link'));
}
links
@@ -84,24 +84,23 @@ export function uiPanelHistory(context) {
.attr('class', 'changeset-osmcha-link')
.attr('href', 'https://osmcha.org/changesets/' + changeset)
.attr('target', '_blank')
.html('OSMCha');
.text('OSMCha');
links
.append('a')
.attr('class', 'changeset-achavi-link')
.attr('href', 'https://overpass-api.de/achavi/?changeset=' + changeset)
.attr('target', '_blank')
.html('Achavi');
.text('Achavi');
}
function redraw(selection) {
var selectedNoteID = context.selectedNoteID();
osm = context.connection();
var selected, note, entity;
if (selectedNoteID && osm) { // selected 1 note
selected = [ t('note.note') + ' ' + selectedNoteID ];
selected = [ t.html('note.note') + ' ' + selectedNoteID ];
note = osm.getNote(selectedNoteID);
} else { // selected 1..n entities
selected = context.selectedIDs()
@@ -115,10 +114,17 @@ export function uiPanelHistory(context) {
selection.html('');
selection
.append('h4')
.attr('class', 'history-heading')
.html(singular || t.html('info_panels.selected', { n: selected.length }));
if (singular) {
selection
.append('h4')
.attr('class', 'history-heading')
.html(singular);
} else {
selection
.append('h4')
.attr('class', 'history-heading')
.call(t.append('info_panels.selected', { n: selected.length }));
}
if (!singular) return;
@@ -134,7 +140,7 @@ export function uiPanelHistory(context) {
if (!note || note.isNew()) {
selection
.append('div')
.html(t.html('info_panels.history.note_no_history'));
.call(t.append('info_panels.history.note_no_history'));
return;
}
@@ -143,20 +149,20 @@ export function uiPanelHistory(context) {
list
.append('li')
.html(t.html('info_panels.history.note_comments') + ':')
.call(t.append('info_panels.history.note_comments', { suffix: ':' }))
.append('span')
.html(note.comments.length);
.text(note.comments.length);
if (note.comments.length) {
list
.append('li')
.html(t.html('info_panels.history.note_created_date') + ':')
.call(t.append('info_panels.history.note_created_date', { suffix: ':' }))
.append('span')
.html(displayTimestamp(note.comments[0].date));
.text(displayTimestamp(note.comments[0].date));
list
.append('li')
.html(t.html('info_panels.history.note_created_user') + ':')
.call(t.append('info_panels.history.note_created_user', { suffix: ':' }))
.call(displayUser, note.comments[0].user);
}
@@ -168,7 +174,7 @@ export function uiPanelHistory(context) {
.attr('href', osm.noteURL(note))
.call(svgIcon('#iD-icon-out-link', 'inline'))
.append('span')
.html(t.html('info_panels.history.note_link_text'));
.call(t.append('info_panels.history.note_link_text'));
}
}
@@ -177,7 +183,7 @@ export function uiPanelHistory(context) {
if (!entity || entity.isNew()) {
selection
.append('div')
.html(t.html('info_panels.history.no_history'));
.call(t.append('info_panels.history.no_history'));
return;
}
@@ -191,8 +197,7 @@ export function uiPanelHistory(context) {
.attr('class', 'view-history-on-osm')
.attr('href', osm.historyURL(entity))
.attr('target', '_blank')
.attr('title', t('info_panels.history.link_text'))
.html('OSM');
.call(t.append('info_panels.history.history_link'));
}
links
.append('a')
@@ -200,31 +205,31 @@ export function uiPanelHistory(context) {
.attr('href', 'https://pewu.github.io/osm-history/#/' + entity.type + '/' + entity.osmId())
.attr('target', '_blank')
.attr('tabindex', -1)
.html('PeWu');
.text('PeWu');
var list = selection
.append('ul');
list
.append('li')
.html(t.html('info_panels.history.version') + ':')
.call(t.append('info_panels.history.version', { suffix: ':' }))
.append('span')
.html(entity.version);
.text(entity.version);
list
.append('li')
.html(t.html('info_panels.history.last_edit') + ':')
.call(t.append('info_panels.history.last_edit', { suffix: ':' }))
.append('span')
.html(displayTimestamp(entity.timestamp));
.text(displayTimestamp(entity.timestamp));
list
.append('li')
.html(t.html('info_panels.history.edited_by') + ':')
.call(t.append('info_panels.history.edited_by', { suffix: ':' }))
.call(displayUser, entity.user);
list
.append('li')
.html(t.html('info_panels.history.changeset') + ':')
.call(t.append('info_panels.history.changeset', { suffix: ':' }))
.call(displayChangeset, entity.changeset);
}
+5 -5
View File
@@ -23,15 +23,15 @@ export function uiPanelLocation(context) {
list
.append('li')
.html(dmsCoordinatePair(coord))
.text(dmsCoordinatePair(coord))
.append('li')
.html(decimalCoordinatePair(coord));
.text(decimalCoordinatePair(coord));
// Location Info
selection
.append('div')
.attr('class', 'location-info')
.html(currLocation || ' ');
.text(currLocation || ' ');
debouncedGetLocation(selection, coord);
}
@@ -42,12 +42,12 @@ export function uiPanelLocation(context) {
if (!services.geocoder) {
currLocation = t('info_panels.location.unknown_location');
selection.selectAll('.location-info')
.html(currLocation);
.text(currLocation);
} else {
services.geocoder.reverse(coord, function(err, result) {
currLocation = result ? result.display_name : t('info_panels.location.unknown_location');
selection.selectAll('.location-info')
.html(currLocation);
.text(currLocation);
});
}
}
+22 -22
View File
@@ -52,7 +52,7 @@ export function uiPanelMeasurement(context) {
if (selectedNoteID && osm) { // selected 1 note
var note = osm.getNote(selectedNoteID);
heading = t('note.note') + ' ' + selectedNoteID;
heading = t.html('note.note') + ' ' + selectedNoteID;
location = note.loc;
geometry = 'note';
@@ -65,7 +65,7 @@ export function uiPanelMeasurement(context) {
});
heading = selected.length === 1 ? selected[0].id :
t('info_panels.selected', { n: selected.length });
t.html('info_panels.selected', { n: selected.length });
if (selected.length) {
var extent = geoExtent();
@@ -129,80 +129,80 @@ export function uiPanelMeasurement(context) {
if (geometry) {
list
.append('li')
.html(t.html('info_panels.measurement.geometry') + ':')
.call(t.append('info_panels.measurement.geometry', { suffix: ':' }))
.append('span')
.html(
closed ? t('info_panels.measurement.closed_' + geometry) : t('geometry.' + geometry)
closed ? t.html('info_panels.measurement.closed_' + geometry) : t.html('geometry.' + geometry)
);
}
if (totalNodeCount) {
list
.append('li')
.html(t.html('info_panels.measurement.node_count') + ':')
.call(t.append('info_panels.measurement.node_count', { suffix: ':' }))
.append('span')
.html(totalNodeCount.toLocaleString(localeCode));
.text(totalNodeCount.toLocaleString(localeCode));
}
if (area) {
list
.append('li')
.html(t.html('info_panels.measurement.area') + ':')
.call(t.append('info_panels.measurement.area', { suffix: ':' }))
.append('span')
.html(displayArea(area, _isImperial));
.text(displayArea(area, _isImperial));
}
if (length) {
list
.append('li')
.html(t.html('info_panels.measurement.' + (closed ? 'perimeter' : 'length')) + ':')
.call(t.append('info_panels.measurement.' + (closed ? 'perimeter' : 'length'), { suffix: ':' }))
.append('span')
.html(displayLength(length, _isImperial));
.text(displayLength(length, _isImperial));
}
if (typeof distance === 'number') {
list
.append('li')
.html(t.html('info_panels.measurement.distance') + ':')
.call(t.append('info_panels.measurement.distance', { suffix: ':' }))
.append('span')
.html(displayLength(distance, _isImperial));
.text(displayLength(distance, _isImperial));
}
if (location) {
coordItem = list
.append('li')
.html(t.html('info_panels.measurement.location') + ':');
.call(t.append('info_panels.measurement.location', { suffix: ':' }));
coordItem.append('span')
.html(dmsCoordinatePair(location));
.text(dmsCoordinatePair(location));
coordItem.append('span')
.html(decimalCoordinatePair(location));
.text(decimalCoordinatePair(location));
}
if (centroid) {
coordItem = list
.append('li')
.html(t.html('info_panels.measurement.centroid') + ':');
.call(t.append('info_panels.measurement.centroid', { suffix: ':' }));
coordItem.append('span')
.html(dmsCoordinatePair(centroid));
.text(dmsCoordinatePair(centroid));
coordItem.append('span')
.html(decimalCoordinatePair(centroid));
.text(decimalCoordinatePair(centroid));
}
if (center) {
coordItem = list
.append('li')
.html(t.html('info_panels.measurement.center') + ':');
.call(t.append('info_panels.measurement.center', { suffix: ':' }));
coordItem.append('span')
.html(dmsCoordinatePair(center));
.text(dmsCoordinatePair(center));
coordItem.append('span')
.html(decimalCoordinatePair(center));
.text(decimalCoordinatePair(center));
}
if (length || area || typeof distance === 'number') {
var toggle = _isImperial ? 'imperial' : 'metric';
selection
.append('a')
.html(t.html('info_panels.measurement.' + toggle))
.call(t.append('info_panels.measurement.' + toggle))
.attr('href', '#')
.attr('class', 'button button-toggle-units')
.on('click', function(d3_event) {
+2 -2
View File
@@ -383,7 +383,7 @@ export function uiPaneHelp(context) {
shortcuts
.append('div')
.html(t.html('shortcuts.title'));
.call(t.append('shortcuts.title'));
var walkthrough = toc
.append('li')
@@ -400,7 +400,7 @@ export function uiPaneHelp(context) {
walkthrough
.append('div')
.html(t.html('splash.walkthrough'));
.call(t.append('splash.walkthrough'));
var helpContent = content
+3 -3
View File
@@ -35,7 +35,7 @@ export function uiPresetList(context) {
var message = messagewrap
.append('h2')
.html(t.html('inspector.choose'));
.call(t.append('inspector.choose'));
var direction = (localizer.textDirection() === 'rtl') ? 'backward' : 'forward';
@@ -99,13 +99,13 @@ export function uiPresetList(context) {
var results, messageText;
if (value.length) {
results = presets.search(value, entityGeometries()[0], _currLoc);
messageText = t('inspector.results', {
messageText = t.html('inspector.results', {
n: results.collection.length,
search: value
});
} else {
results = presetManager.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc);
messageText = t('inspector.choose');
messageText = t.html('inspector.choose');
}
list.call(drawList, results);
message.html(messageText);
+4 -4
View File
@@ -17,13 +17,13 @@ export function uiRestore(context) {
.append('div')
.attr('class', 'modal-section')
.append('h3')
.html(t.html('restore.heading'));
.call(t.append('restore.heading'));
introModal
.append('div')
.attr('class','modal-section')
.append('p')
.html(t.html('restore.description'));
.call(t.append('restore.description'));
let buttonWrap = introModal
.append('div')
@@ -45,7 +45,7 @@ export function uiRestore(context) {
restore
.append('div')
.html(t.html('restore.restore'));
.call(t.append('restore.restore'));
let reset = buttonWrap
.append('button')
@@ -63,7 +63,7 @@ export function uiRestore(context) {
reset
.append('div')
.html(t.html('restore.reset'));
.call(t.append('restore.reset'));
restore.node().focus();
};
+1 -1
View File
@@ -55,7 +55,7 @@ export function uiScale(context) {
selection.select('.scale-text')
.style(localizer.textDirection() === 'ltr' ? 'left' : 'right', (scale.px + 16) + 'px')
.html(scale.text);
.text(scale.text);
}
@@ -103,7 +103,7 @@ export function uiSectionBackgroundDisplayOptions(context) {
.attr('class', 'display-option-resetlink')
.attr('role', 'button')
.attr('href', '#')
.html(t.html('background.reset_all'))
.call(t.append('background.reset_all'))
.on('click', function(d3_event) {
d3_event.preventDefault();
for (var i = 0; i < _sliders.length; i++) {
@@ -119,7 +119,7 @@ export function uiSectionBackgroundDisplayOptions(context) {
.property('value', function(d) { return _options[d]; });
container.selectAll('.display-option-value')
.html(function(d) { return Math.floor(_options[d] * 100) + '%'; });
.text(function(d) { return Math.floor(_options[d] * 100) + '%'; });
container.selectAll('.display-option-reset')
.classed('disabled', function(d) { return _options[d] === 1; });
+4 -4
View File
@@ -70,7 +70,7 @@ export function uiSectionBackgroundList(context) {
minimapLabelEnter
.append('span')
.html(t.html('background.minimap.description'));
.call(t.append('background.minimap.description'));
var panelLabelEnter = bgExtrasListEnter
@@ -93,7 +93,7 @@ export function uiSectionBackgroundList(context) {
panelLabelEnter
.append('span')
.html(t.html('background.panel.description'));
.call(t.append('background.panel.description'));
var locPanelLabelEnter = bgExtrasListEnter
.append('li')
@@ -115,7 +115,7 @@ export function uiSectionBackgroundList(context) {
locPanelLabelEnter
.append('span')
.html(t.html('background.location_panel.description'));
.call(t.append('background.location_panel.description'));
// "Info / Report a Problem" link
@@ -129,7 +129,7 @@ export function uiSectionBackgroundList(context) {
.call(svgIcon('#iD-icon-out-link', 'inline'))
.attr('href', 'https://github.com/openstreetmap/iD/blob/develop/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
.append('span')
.html(t.html('background.imagery_problem_faq'));
.call(t.append('background.imagery_problem_faq'));
_backgroundList
.call(drawListItems, 'radio', function(d3_event, d) {
+1 -1
View File
@@ -132,7 +132,7 @@ export function uiSectionBackgroundOffset(context) {
containerEnter
.append('div')
.attr('class', 'nudge-instructions')
.html(t.html('background.offset'));
.call(t.append('background.offset'));
var nudgeWrapEnter = containerEnter
.append('div')
+4 -4
View File
@@ -29,7 +29,7 @@ export function uiSectionChanges(context) {
.label(function() {
var history = context.history();
var summary = history.difference().summary();
return t('inspector.title_count', { title: t.html('commit.changes'), count: summary.length });
return t.html('inspector.title_count', { title: { html: t.html('commit.changes') }, count: summary.length });
})
.disclosureContent(renderDisclosureContent);
@@ -79,7 +79,7 @@ export function uiSectionChanges(context) {
buttons
.append('strong')
.attr('class', 'entity-type')
.html(function(d) {
.text(function(d) {
var matched = presetManager.match(d.entity, d.graph);
return (matched && matched.name()) || utilDisplayType(d.entity.id);
});
@@ -87,7 +87,7 @@ export function uiSectionChanges(context) {
buttons
.append('span')
.attr('class', 'entity-name')
.html(function(d) {
.text(function(d) {
var name = utilDisplayName(d.entity) || '',
string = '';
if (name !== '') {
@@ -132,7 +132,7 @@ export function uiSectionChanges(context) {
linkEnter
.call(svgIcon('#iD-icon-load', 'inline'))
.append('span')
.html(t.html('commit.download_changes'));
.call(t.append('commit.download_changes'));
function mouseover(d) {
+6 -6
View File
@@ -217,7 +217,7 @@ export function uiSectionDataLayers(context) {
containerEnter
.append('h4')
.attr('class', 'vectortile-header')
.html('Detroit Vector Tiles (Beta)');
.text('Detroit Vector Tiles (Beta)');
containerEnter
.append('ul')
@@ -231,7 +231,7 @@ export function uiSectionDataLayers(context) {
.call(svgIcon('#iD-icon-out-link', 'inline'))
.attr('href', 'https://github.com/osmus/detroit-mapping-challenge')
.append('span')
.html('About these layers');
.text('About these layers');
container = container
.merge(containerEnter);
@@ -265,7 +265,7 @@ export function uiSectionDataLayers(context) {
labelEnter
.append('span')
.html(function(d) { return d.name; });
.text(function(d) { return d.name; });
// Update
li
@@ -324,7 +324,7 @@ export function uiSectionDataLayers(context) {
labelEnter
.append('span')
.html(t.html('map_data.layers.custom.title'));
.call(t.append('map_data.layers.custom.title'));
liEnter
.append('button')
@@ -415,7 +415,7 @@ export function uiSectionDataLayers(context) {
historyPanelLabelEnter
.append('span')
.html(t.html('map_data.history_panel.title'));
.call(t.append('map_data.history_panel.title'));
var measurementPanelLabelEnter = panelsListEnter
.append('li')
@@ -437,7 +437,7 @@ export function uiSectionDataLayers(context) {
measurementPanelLabelEnter
.append('span')
.html(t.html('map_data.measurement_panel.title'));
.call(t.append('map_data.measurement_panel.title'));
}
context.layers().on('change.uiSectionDataLayers', section.reRender);
+2 -2
View File
@@ -24,7 +24,7 @@ export function uiSectionEntityIssues(context) {
return _issues.length > 0;
})
.label(function() {
return t('inspector.title_count', { title: t.html('issues.list_title'), count: _issues.length });
return t.html('inspector.title_count', { title: { html: t.html('issues.list_title') }, count: _issues.length });
})
.disclosureContent(renderDisclosureContent);
@@ -169,7 +169,7 @@ export function uiSectionEntityIssues(context) {
.call(d.reference);
} else {
d3_select(this)
.html(t.html('inspector.no_documentation_key'));
.call(t.append('inspector.no_documentation_key'));
}
});
+2 -2
View File
@@ -33,7 +33,7 @@ export function uiSectionMapFeatures(context) {
.attr('class', 'feature-list-link')
.attr('role', 'button')
.attr('href', '#')
.html(t.html('issues.disable_all'))
.call(t.append('issues.disable_all'))
.on('click', function(d3_event) {
d3_event.preventDefault();
context.features().disableAll();
@@ -44,7 +44,7 @@ export function uiSectionMapFeatures(context) {
.attr('class', 'feature-list-link')
.attr('role', 'button')
.attr('href', '#')
.html(t.html('issues.enable_all'))
.call(t.append('issues.enable_all'))
.on('click', function(d3_event) {
d3_event.preventDefault();
context.features().enableAll();
+1 -1
View File
@@ -273,7 +273,7 @@ export function uiSectionPhotoOverlays(context) {
labelEnter
.append('span')
.html(t.html('photo_overlays.username_filter.title'));
.call(t.append('photo_overlays.username_filter.title'));
labelEnter
.append('input')
+16 -20
View File
@@ -5,22 +5,22 @@ import { svgIcon } from '../../svg/icon';
import { uiSection } from '../section';
export function uiSectionPrivacy(context) {
let section = uiSection('preferences-third-party', context)
.label(t.html('preferences.privacy.title'))
.disclosureContent(renderDisclosureContent);
let _showThirdPartyIcons = prefs('preferences.privacy.thirdpartyicons') || 'true';
function renderDisclosureContent(selection) {
// enter
let privacyOptionsListEnter = selection.selectAll('.privacy-options-list')
selection.selectAll('.privacy-options-list')
.data([0])
.enter()
.append('ul')
.attr('class', 'layer-list privacy-options-list');
let thirdPartyIconsEnter = privacyOptionsListEnter
let thirdPartyIconsEnter = selection.select('.privacy-options-list')
.selectAll('.privacy-third-party-icons-item')
.data([prefs('preferences.privacy.thirdpartyicons') || 'true'])
.enter()
.append('li')
.attr('class', 'privacy-third-party-icons-item')
.append('label')
@@ -32,17 +32,20 @@ export function uiSectionPrivacy(context) {
thirdPartyIconsEnter
.append('input')
.attr('type', 'checkbox')
.on('change', (d3_event) => {
.on('change', (d3_event, d) => {
d3_event.preventDefault();
_showThirdPartyIcons = (_showThirdPartyIcons === 'true') ? 'false' : 'true';
prefs('preferences.privacy.thirdpartyicons', _showThirdPartyIcons);
update();
prefs('preferences.privacy.thirdpartyicons', d === 'true' ? 'false' : 'true');
});
thirdPartyIconsEnter
.append('span')
.html(t.html('preferences.privacy.third_party_icons.description'));
.call(t.append('preferences.privacy.third_party_icons.description'));
// update
selection.selectAll('.privacy-third-party-icons-item')
.classed('active', d => d === 'true')
.select('input')
.property('checked', d => d === 'true');
// Privacy Policy link
selection.selectAll('.privacy-link')
@@ -55,18 +58,11 @@ export function uiSectionPrivacy(context) {
.call(svgIcon('#iD-icon-out-link', 'inline'))
.attr('href', 'https://github.com/openstreetmap/iD/blob/release/PRIVACY.md')
.append('span')
.html(t.html('preferences.privacy.privacy_link'));
.call(t.append('preferences.privacy.privacy_link'));
update();
function update() {
selection.selectAll('.privacy-third-party-icons-item')
.classed('active', (_showThirdPartyIcons === 'true'))
.select('input')
.property('checked', (_showThirdPartyIcons === 'true'));
}
}
prefs.onChange('preferences.privacy.thirdpartyicons', section.reRender);
return section;
}
+5 -5
View File
@@ -33,7 +33,7 @@ export function uiSectionRawMemberEditor(context) {
var gt = entity.members.length > _maxMembers ? '>' : '';
var count = gt + entity.members.slice(0, _maxMembers).length;
return t('inspector.title_count', { title: t.html('inspector.members'), count: count });
return t.html('inspector.title_count', { title: { html: t.html('inspector.members') }, count: count });
})
.disclosureContent(renderDisclosureContent);
@@ -190,7 +190,7 @@ export function uiSectionRawMemberEditor(context) {
labelLink
.append('span')
.attr('class', 'member-entity-type')
.html(function(d) {
.text(function(d) {
var matched = presetManager.match(d.member, context.graph());
return (matched && matched.name()) || utilDisplayType(d.member.id);
});
@@ -198,7 +198,7 @@ export function uiSectionRawMemberEditor(context) {
labelLink
.append('span')
.attr('class', 'member-entity-name')
.html(function(d) { return utilDisplayName(d.member); });
.text(function(d) { return utilDisplayName(d.member); });
label
.append('button')
@@ -221,12 +221,12 @@ export function uiSectionRawMemberEditor(context) {
labelText
.append('span')
.attr('class', 'member-entity-type')
.html(t.html('inspector.' + d.type, { id: d.id }));
.call(t.append('inspector.' + d.type, { id: d.id }));
labelText
.append('span')
.attr('class', 'member-entity-name')
.html(t.html('inspector.incomplete', { id: d.id }));
.call(t.append('inspector.incomplete', { id: d.id }));
label
.append('button')
+4 -4
View File
@@ -31,7 +31,7 @@ export function uiSectionRawMembershipEditor(context) {
var parents = getSharedParentRelations();
var gt = parents.length > _maxMemberships ? '>' : '';
var count = gt + parents.slice(0, _maxMemberships).length;
return t('inspector.title_count', { title: t.html('inspector.relations'), count: count });
return t.html('inspector.title_count', { title: { html: t.html('inspector.relations') }, count: count });
})
.disclosureContent(renderDisclosureContent);
@@ -341,15 +341,15 @@ export function uiSectionRawMembershipEditor(context) {
labelLink
.append('span')
.attr('class', 'member-entity-type')
.html(function(d) {
.text(function(d) {
var matched = presetManager.match(d.relation, context.graph());
return (matched && matched.name()) || t('inspector.relation');
return (matched && matched.name()) || t.html('inspector.relation');
});
labelLink
.append('span')
.attr('class', 'member-entity-name')
.html(function(d) { return utilDisplayName(d.relation); });
.text(function(d) { return utilDisplayName(d.relation); });
labelEnter
.append('button')
+13 -10
View File
@@ -12,13 +12,14 @@ import { utilArrayDifference, utilArrayIdentical } from '../../util/array';
import { utilGetSetValue, utilNoAuto, utilRebind, utilTagDiff } from '../../util';
import { uiTooltip } from '..';
export function uiSectionRawTagEditor(id, context) {
var section = uiSection(id, context)
.classes('raw-tag-editor')
.label(function() {
var count = Object.keys(_tags).filter(function(d) { return d; }).length;
return t('inspector.title_count', { title: t.html('inspector.tags'), count: count });
return t.html('inspector.title_count', { title: { html: t.html('inspector.tags') }, count: count });
})
.expandedByDefault(false)
.disclosureContent(renderDisclosureContent);
@@ -261,7 +262,7 @@ export function uiSectionRawTagEditor(id, context) {
.attr('title', function(d) { return d.key; })
.call(utilGetSetValue, function(d) { return d.key; })
.attr('readonly', function(d) {
return (isReadOnly(d) || (typeof d.value !== 'string')) || null;
return isReadOnly(d) || null;
});
items.selectAll('input.value')
@@ -495,27 +496,29 @@ export function uiSectionRawTagEditor(id, context) {
}
var row = this.parentNode.parentNode;
var inputVal = d3_select(row).selectAll('input.value');
var vNew = context.cleanTagValue(utilGetSetValue(inputVal));
_pendingChange = _pendingChange || {};
if (kOld) {
if (kOld === kNew) return;
// a tag key was renamed
_pendingChange[kNew] = _pendingChange[kOld] || { oldKey: kOld };
_pendingChange[kOld] = undefined;
} else {
// a new tag was added
let row = this.parentNode.parentNode;
let inputVal = d3_select(row).selectAll('input.value');
let vNew = context.cleanTagValue(utilGetSetValue(inputVal));
_pendingChange[kNew] = vNew;
utilGetSetValue(inputVal, vNew);
}
_pendingChange[kNew] = vNew;
// update the ordered key index so this row doesn't change position
var existingKeyIndex = _orderedKeys.indexOf(kOld);
if (existingKeyIndex !== -1) _orderedKeys[existingKeyIndex] = kNew;
d.key = kNew; // update datum to avoid exit/enter on tag update
d.value = vNew;
this.value = kNew;
utilGetSetValue(inputVal, vNew);
scheduleChange();
}
+3 -3
View File
@@ -17,7 +17,7 @@ export function uiSectionSelectionList(context) {
return _selectedIDs.length > 1;
})
.label(function() {
return t('inspector.title_count', { title: t.html('inspector.features'), count: _selectedIDs.length });
return t.html('inspector.title_count', { title: { html: t.html('inspector.features') }, count: _selectedIDs.length });
})
.disclosureContent(renderDisclosureContent);
@@ -116,10 +116,10 @@ export function uiSectionSelectionList(context) {
});
items.selectAll('.entity-type')
.html(function(entity) { return presetManager.match(entity, context.graph()).name(); });
.text(function(entity) { return presetManager.match(entity, context.graph()).name(); });
items.selectAll('.entity-name')
.html(function(d) {
.text(function(d) {
// fetch latest entity
var entity = context.entity(d.id);
return utilDisplayName(entity);
+2 -2
View File
@@ -19,7 +19,7 @@ export function uiSectionValidationIssues(id, severity, context) {
.label(function() {
if (!_issues) return '';
var issueCountText = _issues.length > 1000 ? '1000+' : String(_issues.length);
return t('inspector.title_count', { title: t.html('issues.' + severity + 's.list_title'), count: issueCountText });
return t.html('inspector.title_count', { title: { html: t.html('issues.' + severity + 's.list_title') }, count: issueCountText });
})
.disclosureContent(renderDisclosureContent)
.shouldDisplay(function() {
@@ -174,7 +174,7 @@ export function uiSectionValidationIssues(id, severity, context) {
linkEnter
.append('span')
.attr('class', 'autofix-all-link-text')
.html(t.html('issues.fix_all.title'));
.call(t.append('issues.fix_all.title'));
linkEnter
.append('span')
+3 -3
View File
@@ -46,7 +46,7 @@ export function uiSectionValidationRules(context) {
.attr('class', 'issue-rules-link')
.attr('role', 'button')
.attr('href', '#')
.html(t.html('issues.disable_all'))
.call(t.append('issues.disable_all'))
.on('click', function(d3_event) {
d3_event.preventDefault();
context.validator().disableRules(_ruleKeys);
@@ -57,7 +57,7 @@ export function uiSectionValidationRules(context) {
.attr('class', 'issue-rules-link')
.attr('role', 'button')
.attr('href', '#')
.html(t.html('issues.enable_all'))
.call(t.append('issues.enable_all'))
.on('click', function(d3_event) {
d3_event.preventDefault();
context.validator().disableRules([]);
@@ -106,7 +106,7 @@ export function uiSectionValidationRules(context) {
.html(function(d) {
var params = {};
if (d === 'unsquare_way') {
params.val = '<span class="square-degrees"></span>';
params.val = { html: '<span class="square-degrees"></span>' };
}
return t.html('issues.' + d + '.title', params);
});
+7 -4
View File
@@ -78,7 +78,7 @@ export function uiSectionValidationStatus(context) {
.merge(resetIgnoredEnter);
resetIgnored.select('a')
.html(t('inspector.title_count', { title: t.html('issues.reset_ignored'), count: ignoredIssues.length }));
.html(t.html('inspector.title_count', { title: { html: t.html('issues.reset_ignored') }, count: ignoredIssues.length }));
resetIgnored.on('click', function(d3_event) {
d3_event.preventDefault();
@@ -96,7 +96,8 @@ export function uiSectionValidationStatus(context) {
var hiddenIssues = context.validator().getIssues(hiddenOpts);
if (hiddenIssues.length) {
selection.select('.box .details')
.html(t.html(
.html('')
.call(t.append(
'issues.no_issues.hidden_issues.' + type,
{ count: hiddenIssues.length.toString() }
));
@@ -104,7 +105,8 @@ export function uiSectionValidationStatus(context) {
}
}
selection.select('.box .details')
.html(t.html('issues.no_issues.hidden_issues.none'));
.html('')
.call(t.append('issues.no_issues.hidden_issues.none'));
}
var messageType;
@@ -159,7 +161,8 @@ export function uiSectionValidationStatus(context) {
}
selection.select('.box .message')
.html(t.html('issues.no_issues.message.' + messageType));
.html('')
.call(t.append('issues.no_issues.message.' + messageType));
}
+2 -2
View File
@@ -27,7 +27,7 @@ export function uiSettingsCustomBackground() {
modal.select('.modal-section.header')
.append('h3')
.html(t.html('settings.custom_background.header'));
.call(t.append('settings.custom_background.header'));
var textSection = modal.select('.modal-section.message-text');
@@ -70,7 +70,7 @@ export function uiSettingsCustomBackground() {
buttonSection
.insert('button', '.ok-button')
.attr('class', 'button cancel-button secondary-action')
.html(t.html('confirm.cancel'));
.call(t.append('confirm.cancel'));
buttonSection.select('.cancel-button')
+5 -5
View File
@@ -30,7 +30,7 @@ export function uiSettingsCustomData(context) {
modal.select('.modal-section.header')
.append('h3')
.html(t.html('settings.custom_data.header'));
.call(t.append('settings.custom_data.header'));
var textSection = modal.select('.modal-section.message-text');
@@ -38,7 +38,7 @@ export function uiSettingsCustomData(context) {
textSection
.append('pre')
.attr('class', 'instructions-file')
.html(t.html('settings.custom_data.file.instructions'));
.call(t.append('settings.custom_data.file.instructions'));
textSection
.append('input')
@@ -58,12 +58,12 @@ export function uiSettingsCustomData(context) {
textSection
.append('h4')
.html(t.html('settings.custom_data.or'));
.call(t.append('settings.custom_data.or'));
textSection
.append('pre')
.attr('class', 'instructions-url')
.html(t.html('settings.custom_data.url.instructions'));
.call(t.append('settings.custom_data.url.instructions'));
textSection
.append('textarea')
@@ -79,7 +79,7 @@ export function uiSettingsCustomData(context) {
buttonSection
.insert('button', '.ok-button')
.attr('class', 'button cancel-button secondary-action')
.html(t.html('confirm.cancel'));
.call(t.append('confirm.cancel'));
buttonSection.select('.cancel-button')
+6 -6
View File
@@ -27,7 +27,7 @@ export function uiShortcuts(context) {
.append('div')
.attr('class', 'modal-section header')
.append('h2')
.html(t.html('shortcuts.title'));
.call(t.append('shortcuts.title'));
fileFetcher.get('shortcuts')
.then(function(data) {
@@ -152,11 +152,11 @@ export function uiShortcuts(context) {
selection
.append('kbd')
.attr('class', 'modifier')
.html(function (d) { return uiCmd.display(d); });
.text(function (d) { return uiCmd.display(d); });
selection
.append('span')
.html('+');
.text('+');
});
@@ -201,7 +201,7 @@ export function uiShortcuts(context) {
selection
.append('kbd')
.attr('class', 'shortcut')
.html(function (d) { return d.shortcut; });
.text(function (d) { return d.shortcut; });
}
if (i < nodes.length - 1) {
@@ -211,7 +211,7 @@ export function uiShortcuts(context) {
} else if (i === nodes.length - 1 && d.suffix) {
selection
.append('span')
.html(d.suffix);
.text(d.suffix);
}
});
@@ -223,7 +223,7 @@ export function uiShortcuts(context) {
selection
.append('span')
.html('+');
.text('+');
selection
.append('span')
+1 -1
View File
@@ -41,7 +41,7 @@ export function uiSourceSwitch(context) {
selection
.append('a')
.attr('href', '#')
.html(t.html('source_switch.live'))
.call(t.append('source_switch.live'))
.attr('class', 'live chip')
.on('click', click);
};
+12 -7
View File
@@ -3,6 +3,7 @@ import { fileFetcher } from '../core/file_fetcher';
import { t } from '../core/localizer';
import { uiIntro } from './intro';
import { uiModal } from './modal';
import { uiSectionPrivacy } from './sections/privacy';
export function uiSplash(context) {
@@ -42,7 +43,7 @@ export function uiSplash(context) {
.append('div')
.attr('class','modal-section')
.append('h3')
.html(t.html('splash.welcome'));
.call(t.append('splash.welcome'));
let modalSection = introModal
.append('div')
@@ -52,18 +53,22 @@ export function uiSplash(context) {
.append('p')
.html(t.html('splash.text', {
version: context.version,
website: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/develop/CHANGELOG.md#whats-new">changelog</a>',
github: '<a target="_blank" href="https://github.com/openstreetmap/iD/issues">github.com</a>'
website: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/develop/CHANGELOG.md#whats-new">changelog</a>' },
github: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/issues">github.com</a>' }
}));
modalSection
.append('p')
.html(t.html('splash.privacy', {
updateMessage: updateMessage,
privacyLink: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/release/PRIVACY.md">' +
t('splash.privacy_policy') + '</a>'
privacyLink: { html: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/release/PRIVACY.md">' +
t('splash.privacy_policy') + '</a>' }
}));
uiSectionPrivacy(context)
.label(t.html('splash.privacy_settings'))
.render(modalSection);
let buttonWrap = introModal
.append('div')
.attr('class', 'modal-actions');
@@ -84,7 +89,7 @@ export function uiSplash(context) {
walkthrough
.append('div')
.html(t.html('splash.walkthrough'));
.call(t.append('splash.walkthrough'));
let startEditing = buttonWrap
.append('button')
@@ -99,7 +104,7 @@ export function uiSplash(context) {
startEditing
.append('div')
.html(t.html('splash.start'));
.call(t.append('splash.start'));
modalSelection.select('button.close')
.attr('class','hide');
+7 -7
View File
@@ -22,14 +22,14 @@ export function uiStatus(context) {
} else if (apiStatus === 'rateLimited') {
selection
.html(t.html('osm_api_status.message.rateLimit'))
.call(t.append('osm_api_status.message.rateLimit'))
.append('a')
.attr('href', '#')
.attr('class', 'api-status-login')
.attr('target', '_blank')
.call(svgIcon('#iD-icon-out-link', 'inline'))
.append('span')
.html(t.html('login'))
.call(t.append('login'))
.on('click.login', function(d3_event) {
d3_event.preventDefault();
osm.authenticate();
@@ -47,11 +47,11 @@ export function uiStatus(context) {
// eslint-disable-next-line no-warning-comments
// TODO: nice messages for different error types
selection
.html(t.html('osm_api_status.message.error') + ' ')
.call(t.append('osm_api_status.message.error', { suffix: ' ' }))
.append('a')
.attr('href', '#')
// let the user manually retry their connection directly
.html(t.html('osm_api_status.retry'))
.call(t.append('osm_api_status.retry'))
.on('click.retry', function(d3_event) {
d3_event.preventDefault();
throttledRetry();
@@ -59,9 +59,9 @@ export function uiStatus(context) {
}
} else if (apiStatus === 'readonly') {
selection.html(t.html('osm_api_status.message.readonly'));
selection.call(t.append('osm_api_status.message.readonly'));
} else if (apiStatus === 'offline') {
selection.html(t.html('osm_api_status.message.offline'));
selection.call(t.append('osm_api_status.message.offline'));
}
selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
@@ -70,7 +70,7 @@ export function uiStatus(context) {
osm.on('apiStatusChange.uiStatus', update);
context.history().on('storage_error', () => {
selection.html(t.html('osm_api_status.message.local_storage_full'));
selection.call(t.append('osm_api_status.message.local_storage_full'));
selection.attr('class', 'api-status error');
});

Some files were not shown because too many files have changed in this diff Show More