Merge pull request #4223 from openstreetmap/request_review

Add requesting review
This commit is contained in:
Bryan Housel
2017-08-17 12:15:24 -04:00
committed by GitHub
23 changed files with 1193 additions and 734 deletions
+29 -24
View File
@@ -8,28 +8,32 @@ iD supports several URL parameters. When constructing a URL to a standalone inst
of iD (e.g. `http://preview.ideditor.com/release/`), the following parameters are available
in the hash portion of the URL:
* `map` - A slash separated `zoom/latitude/longitude`. Example:
`map=20.00/38.90085/-77.02271`
* `id` - The character 'n', 'w', or 'r', followed by the OSM ID of a node,
* __`map`__ - A slash separated `zoom/latitude/longitude`.<br/>
_Example:_ `map=20.00/38.90085/-77.02271`
* __`id`__ - The character 'n', 'w', or 'r', followed by the OSM ID of a node,
way or relation, respectively. Selects the specified entity, and, unless
a `map` parameter is also provided, centers the map on it.
* `background` - The value from a `sourcetag` property in iD's
* __`background`__ - The value from a `sourcetag` property in iD's
[imagery list](https://github.com/openstreetmap/iD/blob/master/data/imagery.json),
or a custom tile URL. A custom URL is specified in the format `custom:<url>`,
where the URL can contain the standard tile URL placeholders `{x}`, `{y}` and
`{z}`/`{zoom}`, `{ty}` for flipped TMS-style Y coordinates, and `{switch:a,b,c}` for
DNS multiplexing. Example:
`background=custom:https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png`
* `gpx` - A custom URL for loading a gpx track. Specifying a `gpx` parameter will
automatically enable the gpx layer for display. Example:
`gpx=https://tasks.hotosm.org/project/592/task/16.gpx`
* `offset` - imagery offset in meters, formatted as `east,north`. Example:
`offset=-10,5`
* `comment` - Prefills the changeset comment box, for use when integrating iD with
external task management or quality assurance tools. Example:
`comment=CAR%20crisis%2C%20refugee%20areas%20in%20Cameroon%20%23hotosm-task-592`.
* `rtl=true` - Force iD into right-to-left mode (useful for testing).
* `walkthrough=true` - Start the walkthrough automatically
DNS multiplexing.<br/>
_Example:_ `background=custom:https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png`
* __`gpx`__ - A custom URL for loading a gpx track. Specifying a `gpx` parameter will
automatically enable the gpx layer for display.<br/>
_Example:_ `gpx=https://tasks.hotosm.org/project/592/task/16.gpx`
* __`offset`__ - imagery offset in meters, formatted as `east,north`.<br/>
_Example:_ `offset=-10,5`
* __`comment`__ - Prefills the changeset comment. Pass a url encoded string.<br/>
_Example:_ `comment=CAR%20crisis%2C%20refugee%20areas%20in%20Cameroon`
* __`hashtags`__ - Prefills the changeset hashtags. Pass a url encoded list of event
hashtags separated by commas, semicolons, or spaces. Leading '#' symbols are
optional and will be added automatically. (Note that hashtag-like strings are
automatically detected in the `comment`).<br/>
_Example:_ `hashtags=%23hotosm-task-592,%23MissingMaps`
* __`rtl=true`__ - Force iD into right-to-left mode (useful for testing).
* __`walkthrough=true`__ - Start the walkthrough automatically
##### iD on openstreetmap.org (Rails Port)
@@ -37,14 +41,15 @@ When constructing a URL to an instance of iD embedded in the OpenStreetMap Rails
Port (e.g. `http://www.openstreetmap.org/edit?editor=id`), the following parameters
are available as regular URL query parameters:
* `map` - same as standalone
* `lat`, `lon`, `zoom` - Self-explanatory.
* `node`, `way`, `relation` - Select the specified entity.
* `background` - same as standalone
* `gpx` - same as standalone
* `offset` - same as standalone
* `comment` - same as standalone
* `walkthrough` - same as standalone
* __`map`__ - same as standalone
* __`lat`__, __`lon`__, __`zoom`__ - Self-explanatory.
* __`node`__, __`way`__, __`relation`__ - Select the specified entity.
* __`background`__ - same as standalone
* __`gpx`__ - same as standalone
* __`offset`__ - same as standalone
* __`comment`__ - same as standalone
* __`hashtags`__ - same as standalone
* __`walkthrough`__ - same as standalone
## CSS selectors
+235 -256
View File
@@ -225,6 +225,12 @@ input[type="radio"] {
margin-right: 5px;
margin-top: 3px;
}
[dir='rtl'] input[type="checkbox"],
[dir='rtl'] input[type="radio"] {
float: right;
margin-left: 5px;
margin-right: 0;
}
/* remove bottom border radius when combobox is open */
.combobox + * textarea:focus,
@@ -453,23 +459,37 @@ button.minor:hover {
.button-wrap:last-of-type {
padding-right: 0;
}
[dir='rtl'] .button-wrap:last-of-type {
padding-left: 0;
padding-right: 10px;
}
.joined button {
border-radius:0;
border-right: 1px solid rgba(0,0,0,.5);
}
[dir='rtl'] .joined button {
border-left: 1px solid rgba(0,0,0,.5);
border-right: none;
}
.fillL .joined button {
border-right: 1px solid white;
}
.joined button:first-child {
border-radius:4px 0 0 4px;
border-radius: 4px 0 0 4px;
}
[dir='rtl'] .joined button:first-child {
border-radius: 0 4px 4px 0;
}
.joined button:last-child {
border-right-width: 0;
border-radius:0 4px 4px 0;
border-radius: 0 4px 4px 0;
}
[dir='rtl'] .joined button:last-child {
border-radius: 4px 0 0 4px;
}
button.action {
@@ -516,6 +536,10 @@ button.save.has-count .count {
margin: auto;
margin-left: 9.3333%;
}
[dir='rtl'] button.save.has-count .count {
margin-left: auto;
margin-right: 8%;
}
button.save.has-count .count::before {
content: "";
@@ -532,6 +556,12 @@ button.save.has-count .count::before {
border-right-style: solid;
border-right-color: inherit;
}
[dir='rtl'] button.save.has-count .count::before {
border-left: 6px solid rgba(255,255,255,.5);
border-right: none;
left: auto;
right: -6px;
}
/* Icons */
@@ -551,6 +581,10 @@ button.save.has-count .count::before {
.icon.pre-text {
margin-right: 5px;
}
[dir='rtl'] .icon.pre-text {
margin-left: 5px;
margin-right: 0;
}
.icon.light {
color: #fff;
@@ -583,14 +617,20 @@ button.save.has-count .count::before {
#bar {
position: fixed;
padding: 10px 0;
left:0;
top:0;
right:0;
height:60px;
left: 0;
top: 0;
right: 0;
height: 60px;
z-index: 9;
min-width: 768px;
}
[dir='rtl'] #bar .spacer,
[dir='rtl'] #bar .button-wrap,
[dir='rtl'] #bar .button-wrap button {
float: right;
}
/* Header for modals / panes
------------------------------------------------------- */
@@ -609,6 +649,10 @@ button.save.has-count .count::before {
overflow: hidden;
padding: 20px 20px 20px 40px;
}
[dir='rtl'] .header h3 {
text-align: right;
padding: 20px 40px 20px 20px;
}
.header button,
.modal > button {
@@ -629,12 +673,21 @@ button.save.has-count .count::before {
right: 0;
top: 0;
}
[dir='rtl'] .entity-editor-pane .header button.preset-close,
[dir='rtl'] .preset-list-pane .header button.preset-choose {
left: 0;
right: auto;
}
.entity-editor-pane .header button.preset-choose {
position: absolute;
left: 0;
top: 0;
}
[dir='rtl'] .entity-editor-pane .header button.preset-choose {
left: auto;
right: 0;
}
.preset-choose {
font-size: 16px;
@@ -649,6 +702,10 @@ button.save.has-count .count::before {
height: 60px;
z-index: 50;
}
[dir='rtl'] .modal > button {
left: 0;
right: unset;
}
.footer {
position: absolute;
@@ -680,6 +737,9 @@ button.save.has-count .count::before {
background: #f6f6f6;
-ms-user-select: element;
}
[dir='rtl'] #sidebar {
float: right;
}
.sidebar-component {
position: absolute;
@@ -736,6 +796,10 @@ button.save.has-count .count::before {
top: 80px;
pointer-events: none;
}
[dir='rtl'] #sidebar .search-header .icon {
left: auto;
right: 10px;
}
#sidebar .search-header input {
position: absolute;
@@ -789,6 +853,9 @@ button.save.has-count .count::before {
overflow: hidden;
border-left: 1px solid rgba(0, 0, 0, .1);
}
[dir='rtl'] .feature-list-item .label {
text-align: right;
}
.feature-list-item .label .icon {
opacity: .5;
@@ -816,6 +883,11 @@ button.save.has-count .count::before {
color: #666;
padding-left: 10px;
}
[dir='rtl'] .feature-list-item .entity-name {
padding-left: 0;
padding-right: 10px;
}
/* Presets
------------------------------------------------------- */
@@ -940,6 +1012,19 @@ button.save.has-count .count::before {
height: 24px;
}
[dir='rtl'] .preset-list-button-wrap .preset-icon {
left: auto;
right: auto;
}
[dir='rtl'] .preset-list-button-wrap .preset-icon-28 {
right: 16px;
}
[dir='rtl'] .preset-list-button-wrap .preset-icon-24 {
right: 18px;
}
.preset-list-button .label {
background-color: #f6f6f6;
text-align: left;
@@ -955,7 +1040,15 @@ button.save.has-count .count::before {
overflow: hidden;
border-left: 1px solid rgba(0, 0, 0, .1);
border-radius: 0 3px 3px 0;
}
}
[dir='rtl'] .preset-list-button .label {
text-align: right;
left: 0;
right: 60px;
border-left: none;
border-right: 1px solid rgba(0, 0, 0, .1);
border-radius: 3px 0 0 3px;
}
.preset-list-button:hover .label {
background-color: #ececec;
@@ -971,6 +1064,11 @@ button.save.has-count .count::before {
width: 32px;
background: #fafafa;
}
[dir='rtl'] .preset-list-item button.tag-reference-button {
left: 0;
right: auto;
border-radius: 3px 0 0 3px;
}
.preset-list-item button.tag-reference-button:hover {
background: #f1f1f1;
@@ -1033,13 +1131,13 @@ button.save.has-count .count::before {
margin: 0 20px 10px 20px;
}
.preset-editor .preset-form {
.preset-editor .form-fields-container {
padding: 10px;
margin: 0 10px 10px 10px;
border-radius: 8px;
}
.preset-editor .preset-form:empty {
.preset-editor .form-fields-container:empty {
display: none;
}
@@ -1272,6 +1370,9 @@ button.save.has-count .count::before {
padding: 0 20px 20px 20px;
font-weight: bold;
}
.changeset-editor .more-fields {
padding: 15px 20px 0 20px;
}
.more-fields label {
display: flex;
@@ -1295,6 +1396,9 @@ button.save.has-count .count::before {
padding: 5px 10px;
}
[dir='rtl'] .preset-input-wrap .col6 {
float: right;
}
/* preset form access */
@@ -1754,6 +1858,10 @@ div.combobox {
margin-left: -30px;
vertical-align: top;
}
[dir='rtl'] .combobox-caret {
margin-left: 0;
margin-right: -30px;
}
.combobox-caret::after {
content:"";
@@ -1926,18 +2034,17 @@ button.minor.tag-reference-loading {
clear: both;
}
.tag-reference-body p,
.tag-reference-body img {
margin-top: 20px;
}
.tag-reference-body p:last-child {
padding-bottom: 10px;
.tag-reference-body .tag-reference-description {
margin: 10px 5px 0 5px;
}
.tag-reference-body a {
display: block;
padding-bottom: 10px;
}
.tag-reference-body .tag-reference-description:last-child,
.tag-reference-body a:last-child {
margin-bottom: 15px;
}
.preset-list .tag-reference-body {
@@ -1945,41 +2052,35 @@ button.minor.tag-reference-loading {
width: 100%;
}
.preset-list .tag-reference-body a {
padding-bottom: 20px;
}
.preset-list .tag-reference-body p,
.preset-list .tag-reference-body img {
margin-top: 10px;
}
.raw-tag-editor .tag-reference-body {
border-bottom: 1px solid #ccc;
float: left;
width: 100%;
}
.raw-tag-editor .tag-reference-body p:last-child {
padding-bottom: 20px;
.raw-tag-editor .tag-row.readonly .tag-reference-body {
background: #f6f6f6;
color: #333;
}
.raw-tag-editor .tag-reference-body a {
padding-bottom: 20px;
.raw-tag-editor .tag-row:not(:last-child) .tag-reference-body {
border-bottom: 1px solid #ccc;
}
img.wiki-image {
.raw-tag-editor .tag-row.readonly .tag-reference-body.expanded {
border-top: 1px solid #ccc;
}
img.tag-reference-wiki-image {
float: right;
width: 33.3333%;
width: -webkit-calc(33.3333% - 10px);
width: calc(33.3333% - 10px);
margin-left: 20px;
margin-right: 10px;
border-radius: 4px;
max-height: 200px;
margin-bottom: 20px;
margin: 10px 5px 15px 20px;
}
/* Raw relation membership editor */
.raw-member-editor .member-list li:first-child,
@@ -2057,6 +2158,10 @@ div.full-screen > button:hover {
position: fixed;
z-index: 100;
}
[dir='rtl'] .map-controls {
left: 0;
right: auto;
}
.map-control > button {
width: 40px;
@@ -2078,6 +2183,9 @@ div.full-screen > button:hover {
.zoombuttons button.zoom-in {
border-radius: 4px 0 0 0;
}
[dir='rtl'] .zoombuttons button.zoom-in {
border-radius: 0 4px 0 0;
}
/* Background / Map Data Settings */
@@ -2088,6 +2196,9 @@ div.full-screen > button:hover {
.background-control button {
border-radius: 4px 0 0 0;
}
[dir='rtl'] .background-control button {
border-radius: 0 4px 0 0;
}
.map-data-control,
.background-control {
@@ -2151,6 +2262,10 @@ div.full-screen > button:hover {
float: right;
}
[dir='rtl'] .list-item-gpx-browse svg {
transform: rotateY(180deg);
}
/* make sure tooltip fits in map-control panel */
/* if too wide, placement will be wrong the first time it displays */
.layer-list li.best .tooltip-inner {
@@ -2188,9 +2303,13 @@ div.full-screen > button:hover {
.hide-toggle {
display: block;
padding-left:12px;
padding-left: 12px;
position: relative;
}
[dir='rtl'] .hide-toggle {
padding-left: 0;
padding-right: 12px;
}
.hide-toggle:before {
content: '';
@@ -2204,6 +2323,12 @@ div.full-screen > button:hover {
border-bottom: 4px solid transparent;
border-left: 8px solid #7092ff;
}
[dir='rtl'] .hide-toggle:before {
left: auto;
right: 0;
border-left: none;
border-right: 8px solid #7092ff;
}
.hide-toggle.expanded:before {
border-top: 8px solid #7092ff;
@@ -2211,6 +2336,11 @@ div.full-screen > button:hover {
border-right: 4px solid transparent;
border-left: 4px solid transparent;
}
[dir='rtl'] .hide-toggle.expanded:before {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
}
/* Adjust Alignment controls */
@@ -2341,13 +2471,17 @@ div.full-screen > button:hover {
.opacity-options {
background: url(img/background-pattern-opacity.png) 0 0 repeat;
height:20px;
width:82px;
height: 20px;
width: 82px;
position: absolute;
right: 50px;
top: 20px;
border: 1px solid #ccc;
}
[dir='rtl'] .opacity-options {
left: 50px;
right: auto;
}
.opacity-options li {
height: 100%;
@@ -2357,8 +2491,8 @@ div.full-screen > button:hover {
.opacity-options li .select-box{
position: absolute;
width:20px;
height:18px;
width: 20px;
height: 18px;
z-index: 9999;
}
@@ -2393,6 +2527,12 @@ div.full-screen > button:hover {
border-left: 1px solid #CCC;
border-radius: 0;
}
[dir='rtl'] .map-data-control .layer-list button,
[dir='rtl'] .background-control .layer-list button {
float: left;
border-left: none;
border-right: 1px solid #CCC;
}
.map-data-control .layer-list button .icon,
.background-control .layer-list button .icon {
@@ -2403,6 +2543,10 @@ div.full-screen > button:hover {
.background-control .layer-list button:first-of-type {
border-radius: 0 3px 3px 0;
}
[dir='rtl'] .map-data-control .layer-list button:first-of-type,
[dir='rtl'] .background-control .layer-list button:first-of-type {
border-radius: 3px 0 0 3px;
}
.map-data-control .map-overlay,
.background-control .map-overlay,
@@ -2410,7 +2554,6 @@ div.full-screen > button:hover {
z-index: -1;
}
/* Geolocator */
.geolocate-control {
@@ -2420,6 +2563,9 @@ div.full-screen > button:hover {
.geolocate-control button {
border-radius: 0 0 0 4px;
}
[dir='rtl'] .geolocate-control button {
border-radius: 0 0 4px 0;
}
.map-overlay.content {
position: fixed;
@@ -2429,12 +2575,20 @@ div.full-screen > button:hover {
right: 0;
overflow: auto;
}
[dir='rtl'] .map-overlay.content {
padding: 20px 20px 20px 50px;
left: 0;
right: auto !important;
}
/* Help */
.help-control button {
border-radius: 0 0 0 4px;
}
[dir='rtl'] .help-control button {
border-radius: 0 0 4px 0;
}
.help-wrap p {
font-size: 15px;
@@ -3348,32 +3502,50 @@ img.tile-removing {
float: left;
height: 12px;
min-width: 12px;
font-size:12px;
font-size: 12px;
line-height: 12px;
border-radius:24px;
padding:5px;
background:#7092ff;
color:#fff;
border-radius: 24px;
padding: 5px;
background: #7092ff;
color: #fff;
}
.mode-save .field-warning {
background: #ffb;
border: 1px solid #ccc;
border-radius: 4px;
padding: 10px;
}
.mode-save .field-warning:empty {
display: none;
}
.mode-save .field-warning,
.mode-save .changeset-info,
.mode-save .request-review,
.mode-save .commit-info {
margin-bottom: 10px;
}
.mode-save .changeset-list {
border:1px solid #ccc;
border: 1px solid #ccc;
border-radius: 4px;
background:#fff;
background: #fff;
}
.mode-save .warning-section {
background: #ffb;
}
.mode-save .warning-section .changeset-list button {
border-left: 1px solid #CCC;
border-left: 1px solid #ccc;
}
.mode-save .changeset-list li {
position: relative;
border-top:1px solid #ccc;
padding:5px 10px;
border-top: 1px solid #ccc;
padding: 5px 10px;
cursor: pointer;
}
@@ -3386,8 +3558,8 @@ img.tile-removing {
}
.changeset-list li span.count {
font-size:10px;
color:#555;
font-size: 10px;
color: #555;
}
.mode-save .commit-section .changeset-list button {
@@ -3478,8 +3650,12 @@ img.tile-removing {
}
.notice .zoom-to .icon {
margin-top:10px;
margin-right:10px;
margin-top: 10px;
margin-right: 10px;
}
[dir='rtl'] .notice .zoom-to .icon {
margin-left: 10px;
margin-right: 0;
}
/* Tooltips
@@ -3691,6 +3867,10 @@ img.tile-removing {
.add-point .tooltip {
left: 33.3333% !important;
}
[dir='rtl'] .add-point .tooltip {
left: inherit !important;
}
.add-point .tooltip .tooltip-arrow {
left: 60px;
}
@@ -4023,204 +4203,3 @@ li.hide + li.version .badge .tooltip .tooltip-arrow {
color: #7092FF;
}
/* Right-to-left localization settings */
[dir='rtl'] #sidebar {
float: right;
}
[dir='rtl'] #sidebar .search-header .icon {
left: auto;
right: 10px;
}
/* header */
[dir='rtl'] .header h3 {
text-align: right;
padding: 20px 40px 20px 20px;
}
[dir='rtl'] .entity-editor-pane .header button.preset-choose {
left: auto;
right: 0;
}
[dir='rtl'] .entity-editor-pane .header button.preset-close, [dir='rtl'] .preset-list-pane .header button.preset-choose {
left: 0;
right: auto;
}
[dir='rtl'] .map-data-control .layer-list button, [dir='rtl'] .background-control .layer-list button {
float: left;
border-left: none;
border-right: 1px solid #CCC;
}
[dir='rtl'] .map-data-control .layer-list button:first-of-type, [dir='rtl'] .background-control .layer-list button:first-of-type {
border-radius: 3px 0 0 3px;
}
/* search */
[dir='rtl'] .feature-list-item .label {
text-align: right;
}
[dir='rtl'] .feature-list-item .entity-name {
padding-left: 0;
padding-right: 10px;
}
/* preset form */
[dir='rtl'] .combobox-caret {
margin-left: 0;
margin-right: -30px;
}
[dir='rtl'] .icon.pre-text {
margin-left: 5px;
margin-right: 0;
}
[dir='rtl'] .notice .zoom-to .icon {
margin-left: 10px;
margin-right: 0;
}
[dir='rtl'] .preset-list-button .label {
text-align: right;
left: 0;
right: 60px;
border-left: none;
border-right: 1px solid rgba(0, 0, 0, .1);
border-radius: 3px 0 0 3px;
}
[dir='rtl'] .preset-list-item button.tag-reference-button {
left: 0;
right: auto;
border-radius: 3px 0 0 3px;
}
[dir='rtl'] .preset-list-button-wrap .preset-icon {
left: auto;
right: auto;
}
[dir='rtl'] .preset-list-button-wrap .preset-icon-28 {
right: 16px;
}
[dir='rtl'] .preset-list-button-wrap .preset-icon-24 {
right: 18px;
}
[dir='rtl'] input[type="checkbox"], [dir='rtl'] input[type="radio"] {
float: right;
margin-left: 5px;
margin-right: 0;
}
[dir='rtl'] .preset-input-wrap .col6 {
float: right;
}
/* map control buttons */
[dir='rtl'] .map-controls {
left: 0;
right: auto;
}
[dir='rtl'] .background-control button,
[dir='rtl'] .zoombuttons button.zoom-in {
border-radius: 0 4px 0 0;
}
[dir='rtl'] .help-control button,
[dir='rtl'] .geolocate-control button {
border-radius: 0 0 4px 0;
}
[dir='rtl'] .list-item-gpx-browse svg {
transform: rotateY(180deg);
}
/* map control button overlays */
[dir='rtl'] .map-overlay {
padding: 20px 20px 20px 50px;
left: 0;
right: auto !important;
}
[dir='rtl'] .opacity-options {
left: 50px;
right: auto;
}
[dir='rtl'] .hide-toggle {
padding-left: 0;
padding-right: 12px;
}
[dir='rtl'] .hide-toggle:before {
left: auto;
right: 0;
border-left: none;
border-right: 8px solid #7092ff;
}
[dir='rtl'] .hide-toggle.expanded:before {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
}
/* navbar */
[dir='rtl'] #bar .spacer,
[dir='rtl'] #bar .button-wrap,
[dir='rtl'] #bar .button-wrap button {
float: right;
}
[dir='rtl'] .add-point .tooltip {
left: inherit !important;
}
[dir='rtl'] .button-wrap:last-of-type {
padding-left: 0;
padding-right: 10px;
}
[dir='rtl'] button.save.has-count .count {
margin-left: auto;
margin-right: 8%;
}
[dir='rtl'] button.save.has-count .count::before {
border-left: 6px solid rgba(255,255,255,.5);
border-right: none;
left: auto;
right: -6px;
}
[dir='rtl'] .joined button {
border-left: 1px solid rgba(0,0,0,.5);
border-right: none;
}
[dir='rtl'] .joined button:first-child {
border-radius: 0 4px 4px 0;
}
[dir='rtl'] .joined button:last-child {
border-radius: 4px 0 0 4px;
}
/* modal */
[dir='rtl'] .modal > button {
position: absolute;
left: 0;
right: unset;
top: 0;
}
+1 -2
View File
@@ -254,10 +254,9 @@ en:
rateLimit: The API is limiting anonymous connections. You can fix this by logging in.
commit:
title: Upload to OpenStreetMap
description_placeholder: Brief description of your contributions (required)
message_label: Changeset Comment
upload_explanation: "The changes you upload will be visible on all maps that use OpenStreetMap data."
upload_explanation_with_user: "The changes you upload as {user} will be visible on all maps that use OpenStreetMap data."
request_review: "I would like someone to review my edits."
save: Upload
cancel: Cancel
changes: "{count} Changes"
+11 -1
View File
@@ -339,6 +339,11 @@ en:
collection_times:
# collection_times=*
label: Collection Times
comment:
# comment=*
label: Changeset Comment
# comment field placeholder
placeholder: Brief description of your contributions (required)
communication_multi:
# 'communication:=*'
label: Communication Types
@@ -571,6 +576,11 @@ en:
handrail:
# handrail=*
label: Handrail
hashtags:
# hashtags=*
label: Hashtags
# hashtags field placeholder
placeholder: '#example'
height:
# height=*
label: Height (Meters)
@@ -1218,7 +1228,7 @@ en:
label: People Served
source:
# source=*
label: Source
label: Sources
sport:
# sport=*
label: Sports
+21 -2
View File
@@ -437,6 +437,12 @@
"type": "text",
"label": "Collection Times"
},
"comment": {
"key": "comment",
"type": "textarea",
"label": "Changeset Comment",
"placeholder": "Brief description of your contributions (required)"
},
"communication_multi": {
"key": "communication:",
"type": "multiCombo",
@@ -788,6 +794,12 @@
"type": "check",
"label": "Handrail"
},
"hashtags": {
"key": "hashtags",
"type": "semiCombo",
"label": "Hashtags",
"placeholder": "#example"
},
"height": {
"key": "height",
"type": "number",
@@ -1624,10 +1636,17 @@
},
"source": {
"key": "source",
"type": "text",
"type": "semiCombo",
"icon": "source",
"universal": true,
"label": "Source"
"label": "Sources",
"options": [
"survey",
"local knowledge",
"gps",
"aerial imagery",
"streetlevel imagery"
]
},
"sport_ice": {
"key": "sport",
+6
View File
@@ -0,0 +1,6 @@
{
"key": "comment",
"type": "textarea",
"label": "Changeset Comment",
"placeholder": "Brief description of your contributions (required)"
}
+6
View File
@@ -0,0 +1,6 @@
{
"key": "hashtags",
"type": "semiCombo",
"label": "Hashtags",
"placeholder": "#example"
}
+10 -3
View File
@@ -1,7 +1,14 @@
{
"key": "source",
"type": "text",
"type": "semiCombo",
"icon": "source",
"universal": true,
"label": "Source"
}
"label": "Sources",
"options": [
"survey",
"local knowledge",
"gps",
"aerial imagery",
"streetlevel imagery"
]
}
+10 -3
View File
@@ -328,10 +328,9 @@
},
"commit": {
"title": "Upload to OpenStreetMap",
"description_placeholder": "Brief description of your contributions (required)",
"message_label": "Changeset Comment",
"upload_explanation": "The changes you upload will be visible on all maps that use OpenStreetMap data.",
"upload_explanation_with_user": "The changes you upload as {user} will be visible on all maps that use OpenStreetMap data.",
"request_review": "I would like someone to review my edits.",
"save": "Upload",
"cancel": "Cancel",
"changes": "{count} Changes",
@@ -1354,6 +1353,10 @@
"collection_times": {
"label": "Collection Times"
},
"comment": {
"label": "Changeset Comment",
"placeholder": "Brief description of your contributions (required)"
},
"communication_multi": {
"label": "Communication Types"
},
@@ -1566,6 +1569,10 @@
"handrail": {
"label": "Handrail"
},
"hashtags": {
"label": "Hashtags",
"placeholder": "#example"
},
"height": {
"label": "Height (Meters)"
},
@@ -2094,7 +2101,7 @@
"label": "Type"
},
"source": {
"label": "Source"
"label": "Sources"
},
"sport_ice": {
"label": "Sports"
+7 -1
View File
@@ -37,7 +37,9 @@ export function behaviorHash(context) {
var center = map.center(),
zoom = map.zoom(),
precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2)),
q = _.omit(utilStringQs(window.location.hash.substring(1)), ['comment', 'walkthrough']),
q = _.omit(utilStringQs(window.location.hash.substring(1)),
['comment', 'hashtags', 'walkthrough']
),
newParams = {};
delete q.id;
@@ -99,6 +101,10 @@ export function behaviorHash(context) {
context.storage('commentDate', Date.now());
}
if (q.hashtags) {
context.storage('hashtags', q.hashtags);
}
if (q.walkthrough === 'true') {
hash.startWalkthrough = true;
}
+11
View File
@@ -1,6 +1,7 @@
import * as d3 from 'd3';
import _ from 'lodash';
import { d3keybinding } from '../lib/d3.keybinding.js';
import { t } from '../util/locale';
import { JXON } from '../util/jxon';
@@ -34,6 +35,8 @@ export function modeSave(context) {
id: 'save'
};
var keybinding = d3keybinding('select');
var commit = uiCommit(context)
.on('cancel', cancel)
.on('save', save);
@@ -360,6 +363,12 @@ export function modeSave(context) {
context.ui().sidebar.show(commit);
}
keybinding
.on('⎋', cancel, true);
d3.select(document)
.call(keybinding);
context.container().selectAll('#content')
.attr('class', 'inactive');
@@ -381,6 +390,8 @@ export function modeSave(context) {
mode.exit = function() {
keybinding.off();
context.container().selectAll('#content')
.attr('class', 'active');
+141
View File
@@ -0,0 +1,141 @@
import * as d3 from 'd3';
import _ from 'lodash';
import { d3combobox } from '../lib/d3.combobox.js';
import { t } from '../util/locale';
import { svgIcon } from '../svg';
import { uiField } from './field';
import { uiFormFields } from './form_fields';
import { utilRebind, utilTriggerEvent } from '../util';
export function uiChangesetEditor(context) {
var dispatch = d3.dispatch('change'),
formFields = uiFormFields(context),
fieldsArr,
tags,
changesetId;
function changesetEditor(selection) {
render(selection);
}
function render(selection) {
var initial = false;
if (!fieldsArr) {
initial = true;
var presets = context.presets();
fieldsArr = [
uiField(context, presets.field('comment'), null, { show: true, revert: false }),
uiField(context, presets.field('source'), null, { show: false, revert: false }),
uiField(context, presets.field('hashtags'), null, { show: false, revert: false }),
];
fieldsArr.forEach(function(field) {
field
.on('change', function(t, onInput) {
dispatch.call('change', field, t, onInput);
});
});
}
fieldsArr.forEach(function(field) {
field
.tags(tags);
});
selection
.call(formFields.fieldsArr(fieldsArr));
if (initial) {
var commentField = selection.select('#preset-input-comment'),
commentNode = commentField.node();
if (commentNode) {
commentNode.focus();
commentNode.select();
}
// trigger a 'blur' event so that comment field can be cleaned
// and checked for hashtags, even if retrieved from localstorage
utilTriggerEvent(commentField, 'blur');
var osm = context.connection();
if (osm) {
osm.userChangesets(function (err, changesets) {
if (err) return;
var comments = changesets.map(function(changeset) {
return {
title: changeset.tags.comment,
value: changeset.tags.comment
};
});
commentField
.call(d3combobox()
.container(context.container())
.caseSensitive(true)
.data(_.uniqBy(comments, 'title'))
);
});
}
}
// Add warning if comment mentions Google
var hasGoogle = tags.comment.match(/google/i);
var commentWarning = selection.select('.form-field-comment').selectAll('.comment-warning')
.data(hasGoogle ? [0] : []);
commentWarning.exit()
.transition()
.duration(200)
.style('opacity', 0)
.remove();
var commentEnter = commentWarning.enter()
.insert('div', '.tag-reference-body')
.attr('class', 'field-warning comment-warning')
.style('opacity', 0);
commentEnter
.append('a')
.attr('target', '_blank')
.attr('tabindex', -1)
.call(svgIcon('#icon-alert', 'inline'))
.attr('href', t('commit.google_warning_link'))
.append('span')
.text(t('commit.google_warning'));
commentEnter
.transition()
.duration(200)
.style('opacity', 1);
}
changesetEditor.tags = function(_) {
if (!arguments.length) return tags;
tags = _;
// Don't reset fieldsArr here.
return changesetEditor;
};
changesetEditor.changesetID = function(_) {
if (!arguments.length) return changesetId;
if (changesetId === _) return changesetEditor;
changesetId = _;
fieldsArr = null;
return changesetEditor;
};
return utilRebind(changesetEditor, dispatch, 'on');
}
+257 -304
View File
@@ -1,187 +1,140 @@
import * as d3 from 'd3';
import _ from 'lodash';
import { t } from '../util/locale';
import { d3combobox } from '../lib/d3.combobox.js';
import { osmChangeset } from '../osm';
import { modeSelect } from '../modes';
import { svgIcon } from '../svg';
import { tooltip } from '../util/tooltip';
import { uiChangesetEditor } from './changeset_editor';
import { uiCommitChanges } from './commit_changes';
import { uiCommitWarnings } from './commit_warnings';
import { uiRawTagEditor } from './raw_tag_editor';
import { utilDetect } from '../util/detect';
import {
utilDisplayName,
utilDisplayType,
utilEntityOrMemberSelector,
utilRebind,
utilTriggerEvent
} from '../util';
import { utilRebind } from '../util';
var changeset;
var readOnlyTags = ['created_by', 'imagery_used', 'host', 'locale'];
var readOnlyTags = [
/^changesets_count$/,
/^created_by$/,
/^ideditor:/,
/^imagery_used$/,
/^host$/,
/^locale$/
];
export function uiCommit(context) {
var dispatch = d3.dispatch('cancel', 'save');
var dispatch = d3.dispatch('cancel', 'save'),
userDetails,
_selection;
var changesetEditor = uiChangesetEditor(context)
.on('change', changeTags);
var rawTagEditor = uiRawTagEditor(context)
.on('change', changeTags);
var commitChanges = uiCommitChanges(context);
var commitWarnings = uiCommitWarnings(context);
function commit(selection) {
_selection = selection;
var osm = context.connection();
if (!osm) return;
var comment = context.storage('comment') || '',
commentDate = +context.storage('commentDate') || 0,
hashtags = context.storage('hashtags'),
currDate = Date.now(),
cutoff = 2 * 86400 * 1000; // 2 days
// expire stored comment and hashtags after cutoff datetime - #3947
if (commentDate > currDate || currDate - commentDate > cutoff) {
comment = '';
hashtags = undefined;
}
var tags;
if (!changeset) {
var detected = utilDetect(),
tags = {
created_by: ('iD ' + context.version).substr(0, 255),
imagery_used: context.history().imageryUsed().join(';').substr(0, 255),
host: detected.host.substr(0, 255),
locale: detected.locale.substr(0, 255)
};
var detected = utilDetect();
tags = {
comment: comment,
created_by: ('iD ' + context.version).substr(0, 255),
imagery_used: context.history().imageryUsed().join(';').substr(0, 255),
host: detected.host.substr(0, 255),
locale: detected.locale.substr(0, 255)
};
if (hashtags) {
tags.hashtags = hashtags;
}
changeset = new osmChangeset({ tags: tags });
}
tags = _.clone(changeset.tags);
var changes = context.history().changes(),
summary = context.history().difference().summary(),
rawTagEditor = uiRawTagEditor(context).on('change', changeTags),
comment = context.storage('comment') || '',
commentDate = +context.storage('commentDate') || 0,
currDate = Date.now(),
cutoff = 2 * 86400 * 1000; // 2 days
var header = selection.selectAll('.header')
.data([0]);
// expire the stored comment if it is too old - #3947
if (commentDate > currDate || currDate - commentDate > cutoff) {
comment = '';
}
selection
header.enter()
.append('div')
.attr('class', 'header fillL')
.append('h3')
.text(t('commit.title'));
var body = selection
var body = selection.selectAll('.body')
.data([0]);
body = body.enter()
.append('div')
.attr('class', 'body');
.attr('class', 'body')
.merge(body);
var commentSection = body
// Changeset Section
var changesetSection = body.selectAll('.changeset-editor')
.data([0]);
changesetSection = changesetSection.enter()
.append('div')
.attr('class', 'modal-section form-field commit-form');
.attr('class', 'modal-section changeset-editor')
.merge(changesetSection);
commentSection
.append('label')
.attr('class', 'form-label')
.text(t('commit.message_label'));
var commentField = commentSection
.append('textarea')
.attr('class', 'commit-form-comment')
.attr('placeholder', t('commit.description_placeholder'))
.attr('maxlength', 255)
.property('value', comment)
.on('input.save', change(true))
.on('change.save', change())
.on('blur.save', function() {
context.storage('comment', this.value);
context.storage('commentDate', Date.now());
});
commentField.node().select();
osm.userChangesets(function (err, changesets) {
if (err) return;
var comments = changesets.map(function(changeset) {
return {
title: changeset.tags.comment,
value: changeset.tags.comment
};
});
commentField
.call(d3combobox()
.container(context.container())
.caseSensitive(true)
.data(_.uniqBy(comments, 'title'))
);
});
var clippyArea = commentSection.append('div')
.attr('class', 'clippy-area');
var changeSetInfo = commentSection.append('div')
.attr('class', 'changeset-info');
changeSetInfo.append('a')
.attr('target', '_blank')
.attr('tabindex', -1)
.call(svgIcon('#icon-out-link', 'inline'))
.attr('href', t('commit.about_changeset_comments_link'))
.append('span')
.text(t('commit.about_changeset_comments'));
// Warnings
var warnings = body.selectAll('div.warning-section')
.data([context.history().validate(changes)]);
warnings = warnings.enter()
.append('div')
.attr('class', 'modal-section warning-section fillL2')
.style('display', function(d) { return _.isEmpty(d) ? 'none' : null; })
.style('background', '#ffb')
.merge(warnings);
warnings
.append('h3')
.text(t('commit.warnings'));
warnings
.append('ul')
.attr('class', 'changeset-list');
var warningLi = warnings.select('ul').selectAll('li')
.data(function(d) { return d; });
warningLi = warningLi.enter()
.append('li')
.on('mouseover', mouseover)
.on('mouseout', mouseout)
.on('click', warningClick)
.merge(warningLi);
warningLi
.call(svgIcon('#icon-alert', 'pre-text'));
warningLi
.append('strong')
.text(function(d) { return d.message; });
warningLi.filter(function(d) { return d.tooltip; })
.call(tooltip()
.title(function(d) { return d.tooltip; })
.placement('top')
changesetSection
.call(changesetEditor
.changesetID(changeset.id)
.tags(tags)
);
// Upload Explanation
var saveSection = body
.append('div')
.attr('class','modal-section save-section fillL cf');
// Warnings
body.call(commitWarnings);
var prose = saveSection
// Upload Explanation
var saveSection = body.selectAll('.save-section')
.data([0]);
saveSection = saveSection.enter()
.append('div')
.attr('class','modal-section save-section fillL cf')
.merge(saveSection);
var prose = saveSection.selectAll('.commit-info')
.data([0]);
prose = prose.enter()
.append('p')
.attr('class', 'commit-info')
.html(t('commit.upload_explanation'));
.text(t('commit.upload_explanation'))
.merge(prose);
osm.userDetails(function(err, user) {
if (err) return;
var userLink = d3.select(document.createElement('div'));
userDetails = user;
if (user.image_url) {
userLink
.append('img')
@@ -202,217 +155,217 @@ export function uiCommit(context) {
});
var requestReview = saveSection.selectAll('.request-review')
.data([0]);
requestReview = requestReview.enter()
.append('p')
.attr('class', 'request-review')
.text(t('commit.request_review'))
.merge(requestReview);
var requestReviewField = requestReview.selectAll('input')
.data([0]);
requestReviewField = requestReviewField.enter()
.append('input')
.attr('type', 'checkbox')
.merge(requestReviewField);
requestReviewField
.property('checked', isReviewRequested(changeset.tags))
.on('change', toggleRequestReview);
// Buttons
var buttonSection = saveSection
var buttonSection = saveSection.selectAll('.buttons')
.data([0]);
// enter
var buttonEnter = buttonSection.enter()
.append('div')
.attr('class', 'buttons fillL cf');
var cancelButton = buttonSection
buttonEnter
.append('button')
.attr('class', 'secondary-action col5 button cancel-button')
.on('click.cancel', function() {
dispatch.call('cancel');
});
cancelButton
.append('span')
.attr('class', 'label')
.text(t('commit.cancel'));
var saveButton = buttonSection
buttonEnter
.append('button')
.attr('class', 'action col5 button save-button')
.append('span')
.attr('class', 'label')
.text(t('commit.save'));
// update
buttonSection = buttonSection
.merge(buttonEnter);
buttonSection.selectAll('.cancel-button')
.on('click.cancel', function() {
dispatch.call('cancel');
});
buttonSection.selectAll('.save-button')
.attr('disabled', function() {
var n = d3.select('.commit-form textarea').node();
var n = d3.select('#preset-input-comment').node();
return (n && n.value.length) ? null : true;
})
.on('click.save', function() {
dispatch.call('save', this, changeset);
});
saveButton
.append('span')
.attr('class', 'label')
.text(t('commit.save'));
// Raw Tag Editor
var tagSection = body
var tagSection = body.selectAll('.tag-section.raw-tag-editor')
.data([0]);
tagSection = tagSection.enter()
.append('div')
.attr('class', 'modal-section tag-section raw-tag-editor');
.attr('class', 'modal-section tag-section raw-tag-editor')
.merge(tagSection);
var expanded = !tagSection.selectAll('a.hide-toggle.expanded').empty();
tagSection
.call(rawTagEditor
.expanded(expanded)
.readOnlyTags(readOnlyTags)
.tags(_.clone(changeset.tags))
);
// Changes
var changeSection = body
.append('div')
.attr('class', 'commit-section modal-section fillL2');
// Change summary
body.call(commitChanges);
changeSection.append('h3')
.text(t('commit.changes', { count: summary.length }));
var li = changeSection
.append('ul')
.attr('class', 'changeset-list')
.selectAll('li')
.data(summary);
function toggleRequestReview() {
var rr = requestReviewField.property('checked');
updateChangeset({ review_requested: (rr ? 'yes' : undefined) });
li = li.enter()
.append('li')
.on('mouseover', mouseover)
.on('mouseout', mouseout)
.on('click', zoomToEntity)
.merge(li);
var expanded = !tagSection.selectAll('a.hide-toggle.expanded').empty();
li.each(function(d) {
d3.select(this)
.call(svgIcon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
tagSection
.call(rawTagEditor
.expanded(expanded)
.readOnlyTags(readOnlyTags)
.tags(_.clone(changeset.tags))
);
}
}
function changeTags(changed, onInput) {
if (changed.hasOwnProperty('comment')) {
if (changed.comment === undefined) {
changed.comment = '';
}
if (!onInput) {
context.storage('comment', changed.comment);
context.storage('commentDate', Date.now());
}
}
updateChangeset(changed, onInput);
if (_selection) {
_selection.call(commit);
}
}
function findHashtags(tags) {
return _.unionBy(commentTags(), hashTags(), function (s) {
return s.toLowerCase();
});
li.append('span')
.attr('class', 'change-type')
.text(function(d) { return t('commit.' + d.changeType) + ' '; });
li.append('strong')
.attr('class', 'entity-type')
.text(function(d) {
var matched = context.presets().match(d.entity, d.graph);
return (matched && matched.name()) || utilDisplayType(d.entity.id);
});
li.append('span')
.attr('class', 'entity-name')
.text(function(d) {
var name = utilDisplayName(d.entity) || '',
string = '';
if (name !== '') string += ':';
return string += ' ' + name;
});
li.style('opacity', 0)
.transition()
.style('opacity', 1);
// Call change() off the bat, in case a changeset
// comment is recovered from localStorage
utilTriggerEvent(commentField, 'input');
function mouseover(d) {
if (d.entity) {
context.surface().selectAll(
utilEntityOrMemberSelector([d.entity.id], context.graph())
).classed('hover', true);
}
// Extract hashtags from `comment`
function commentTags() {
return tags.comment.match(/#[^\s\#]+/g);
}
function mouseout() {
context.surface().selectAll('.hover')
.classed('hover', false);
// Extract and clean hashtags from `hashtags`
function hashTags() {
var t = tags.hashtags || '';
return t
.split(/[,;\s]+/)
.map(function (s) {
if (s[0] !== '#') { s = '#' + s; } // prepend '#'
var matched = s.match(/#[^\s\#]+/g); // match valid hashtags
return matched && matched[0];
}).filter(Boolean); // exclude falsey
}
}
function warningClick(d) {
if (d.entity) {
context.map().zoomTo(d.entity);
context.enter(modeSelect(context, [d.entity.id]));
}
}
function isReviewRequested(tags) {
var rr = tags.review_requested;
if (rr === undefined) return false;
rr = rr.trim().toLowerCase();
return !(rr === '' || rr === 'no');
}
function zoomToEntity(change) {
var entity = change.entity;
if (change.changeType !== 'deleted' &&
context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
context.map().zoomTo(entity);
context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph()))
.classed('hover', true);
}
}
function updateChangeset(changed, onInput) {
var tags = _.clone(changeset.tags);
_.forEach(changed, function(v, k) {
k = k.trim().substr(0, 255);
if (readOnlyTags.indexOf(k) !== -1) return;
function checkComment(comment) {
// Save button disabled if there is no comment..
d3.selectAll('.save-section .save-button')
.attr('disabled', (comment.length ? null : true));
// Warn if comment mentions Google..
var googleWarning = clippyArea
.html('')
.selectAll('a')
.data(comment.match(/google/i) ? [true] : []);
googleWarning.exit()
.remove();
googleWarning.enter()
.append('a')
.attr('target', '_blank')
.attr('tabindex', -1)
.call(svgIcon('#icon-alert', 'inline'))
.attr('href', t('commit.google_warning_link'))
.append('span')
.text(t('commit.google_warning'));
}
function change(onInput) {
return function() {
var comment = commentField.property('value').trim();
if (!onInput) {
commentField.property('value', comment);
}
checkComment(comment);
var changeset = updateChangeset({ comment: comment });
var expanded = !tagSection.selectAll('a.hide-toggle.expanded').empty();
tagSection
.call(rawTagEditor
.expanded(expanded)
.readOnlyTags(readOnlyTags)
.tags(_.clone(changeset.tags))
);
};
}
function changeTags(changed) {
if (changed.hasOwnProperty('comment')) {
if (changed.comment === undefined) {
changed.comment = '';
}
changed.comment = changed.comment.trim();
commentField.property('value', changed.comment);
}
updateChangeset(changed);
utilTriggerEvent(commentField, 'input');
}
function updateChangeset(changed) {
var tags = _.clone(changeset.tags);
_.forEach(changed, function(v, k) {
k = k.trim().substr(0, 255);
if (readOnlyTags.indexOf(k) !== -1) return;
if (k !== '' && v !== undefined) {
tags[k] = v.trim().substr(0, 255);
if (k !== '' && v !== undefined) {
if (onInput) {
tags[k] = v;
} else {
delete tags[k];
tags[k] = v.trim().substr(0, 255);
}
});
if (!_.isEqual(changeset.tags, tags)) {
changeset = changeset.update({ tags: tags });
} else {
delete tags[k];
}
});
return changeset;
if (!onInput) {
var arr = findHashtags(tags);
if (arr.length) {
tags.hashtags = arr.join(';').substr(0, 255);
context.storage('hashtags', tags.hashtags);
} else {
delete tags.hashtags;
context.storage('hashtags', null);
}
}
// always update userdetails, just in case user reauthenticates as someone else
if (userDetails && userDetails.changesets_count !== undefined) {
tags.changesets_count = String(userDetails.changesets_count);
// first 100 edits - new user
if (parseInt(tags.changesets_count, 10) < 100) {
var s;
s = context.storage('walkthrough_completed');
if (s) {
tags['ideditor:walkthrough_completed'] = s;
}
s = context.storage('walkthrough_progress');
if (s) {
tags['ideditor:walkthrough_progress'] = s;
}
s = context.storage('walkthrough_started');
if (s) {
tags['ideditor:walkthrough_started'] = s;
}
}
} else {
delete tags.changesets_count;
}
if (!_.isEqual(changeset.tags, tags)) {
changeset = changeset.update({ tags: tags });
}
}
+116
View File
@@ -0,0 +1,116 @@
import * as d3 from 'd3';
import { t } from '../util/locale';
import { svgIcon } from '../svg';
import {
utilDisplayName,
utilDisplayType,
utilEntityOrMemberSelector
} from '../util';
export function uiCommitChanges(context) {
function commitChanges(selection) {
var summary = context.history().difference().summary();
var container = selection.selectAll('.modal-section.commit-section')
.data([0]);
var containerEnter = container.enter()
.append('div')
.attr('class', 'commit-section modal-section fillL2');
containerEnter
.append('h3')
.text(t('commit.changes', { count: summary.length }));
containerEnter
.append('ul')
.attr('class', 'changeset-list');
container = containerEnter
.merge(container);
var items = container.select('ul').selectAll('li')
.data(summary);
var itemsEnter = items.enter()
.append('li')
.attr('class', 'change-item');
itemsEnter
.each(function(d) {
d3.select(this)
.call(svgIcon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
});
itemsEnter
.append('span')
.attr('class', 'change-type')
.text(function(d) { return t('commit.' + d.changeType) + ' '; });
itemsEnter
.append('strong')
.attr('class', 'entity-type')
.text(function(d) {
var matched = context.presets().match(d.entity, d.graph);
return (matched && matched.name()) || utilDisplayType(d.entity.id);
});
itemsEnter
.append('span')
.attr('class', 'entity-name')
.text(function(d) {
var name = utilDisplayName(d.entity) || '',
string = '';
if (name !== '') {
string += ':';
}
return string += ' ' + name;
});
itemsEnter
.style('opacity', 0)
.transition()
.style('opacity', 1);
items = itemsEnter
.merge(items);
items
.on('mouseover', mouseover)
.on('mouseout', mouseout)
.on('click', zoomToEntity);
function mouseover(d) {
if (d.entity) {
context.surface().selectAll(
utilEntityOrMemberSelector([d.entity.id], context.graph())
).classed('hover', true);
}
}
function mouseout() {
context.surface().selectAll('.hover')
.classed('hover', false);
}
function zoomToEntity(change) {
var entity = change.entity;
if (change.changeType !== 'deleted' &&
context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
context.map().zoomTo(entity);
context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph()))
.classed('hover', true);
}
}
}
return commitChanges;
}
+95
View File
@@ -0,0 +1,95 @@
import { t } from '../util/locale';
import { modeSelect } from '../modes';
import { svgIcon } from '../svg';
import { tooltip } from '../util/tooltip';
import { utilEntityOrMemberSelector } from '../util';
export function uiCommitWarnings(context) {
function commitWarnings(selection) {
var changes = context.history().changes();
var warnings = context.history().validate(changes);
var container = selection.selectAll('.warning-section')
.data(warnings.length ? [0] : []);
container.exit()
.remove();
var containerEnter = container.enter()
.append('div')
.attr('class', 'modal-section warning-section fillL2');
containerEnter
.append('h3')
.text(t('commit.warnings'));
containerEnter
.append('ul')
.attr('class', 'changeset-list');
container = containerEnter
.merge(container);
var items = container.select('ul').selectAll('li')
.data(warnings);
items.exit()
.remove();
var itemsEnter = items.enter()
.append('li')
.attr('class', 'warning-item');
itemsEnter
.call(svgIcon('#icon-alert', 'pre-text'));
itemsEnter
.append('strong')
.text(function(d) { return d.message; });
itemsEnter.filter(function(d) { return d.tooltip; })
.call(tooltip()
.title(function(d) { return d.tooltip; })
.placement('top')
);
items = itemsEnter
.merge(items);
items
.on('mouseover', mouseover)
.on('mouseout', mouseout)
.on('click', warningClick);
function mouseover(d) {
if (d.entity) {
context.surface().selectAll(
utilEntityOrMemberSelector([d.entity.id], context.graph())
).classed('hover', true);
}
}
function mouseout() {
context.surface().selectAll('.hover')
.classed('hover', false);
}
function warningClick(d) {
if (d.entity) {
context.map().zoomTo(d.entity);
context.enter(modeSelect(context, [d.entity.id]));
}
}
}
return commitWarnings;
}
+25 -16
View File
@@ -10,7 +10,10 @@ import { utilRebind } from '../util';
export function uiField(context, presetField, entity, options) {
options = _.extend({
show: true,
wrap: true
wrap: true,
remove: true,
revert: true,
info: true
}, options);
var dispatch = d3.dispatch('change'),
@@ -24,7 +27,7 @@ export function uiField(context, presetField, entity, options) {
dispatch.call('change', field, t, onInput);
});
if (field.impl.entity) {
if (entity && field.impl.entity) {
field.impl.entity(entity);
}
@@ -34,6 +37,7 @@ export function uiField(context, presetField, entity, options) {
function isModified() {
if (!entity) return false;
var original = context.graph().base().entities[entity.id];
return _.some(field.keys, function(key) {
return original ? tags[key] !== original.tags[key] : tags[key];
@@ -51,6 +55,7 @@ export function uiField(context, presetField, entity, options) {
function revert(d) {
d3.event.stopPropagation();
d3.event.preventDefault();
if (!entity) return false;
var original = context.graph().base().entities[entity.id],
t = {};
@@ -96,19 +101,23 @@ export function uiField(context, presetField, entity, options) {
.append('div')
.attr('class', 'form-label-button-wrap');
wrap
.append('button')
.attr('class', 'remove-icon')
.attr('tabindex', -1)
.call(svgIcon('#operation-delete'));
if (options.remove) {
wrap
.append('button')
.attr('class', 'remove-icon')
.attr('tabindex', -1)
.call(svgIcon('#operation-delete'));
}
wrap
.append('button')
.attr('class', 'modified-icon')
.attr('tabindex', -1)
.call(
(textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
);
if (options.revert) {
wrap
.append('button')
.attr('class', 'modified-icon')
.attr('tabindex', -1)
.call(
(textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
);
}
}
@@ -126,7 +135,7 @@ export function uiField(context, presetField, entity, options) {
.classed('modified', isModified())
.classed('present', isPresent())
.each(function(d) {
if (options.wrap) {
if (options.wrap && options.info) {
var referenceKey = d.key;
if (d.type === 'multiCombo') { // lookup key without the trailing ':'
referenceKey = referenceKey.replace(/:$/, '');
@@ -141,7 +150,7 @@ export function uiField(context, presetField, entity, options) {
d3.select(this)
.call(d.impl);
if (options.wrap) {
if (options.wrap && options.info) {
d3.select(this)
.call(reference.body)
.select('.form-label-button-wrap')
+8 -3
View File
@@ -161,12 +161,17 @@ export function uiFieldCombo(field, context) {
query = country + ':';
}
taginfo[fn]({
var params = {
debounce: (q !== ''),
key: field.key,
geometry: context.geometry(entity.id),
query: query
}, function(err, data) {
};
if (entity) {
params.geometry = context.geometry(entity.id);
}
taginfo[fn](params, function(err, data) {
if (err) return;
if (hasCountryPrefix) {
data = _.filter(data, function(d) {
+122
View File
@@ -0,0 +1,122 @@
import * as d3 from 'd3';
import { d3combobox } from '../lib/d3.combobox.js';
import { t } from '../util/locale';
import { utilGetSetValue, utilNoAuto } from '../util';
export function uiFormFields(context) {
var fieldsArr;
function formFields(selection, klass) {
render(selection, klass);
}
function render(selection, klass) {
var shown = fieldsArr.filter(function(field) { return field.isShown(); }),
notShown = fieldsArr.filter(function(field) { return !field.isShown(); });
var container = selection.selectAll('.form-fields-container')
.data([0]);
container = container.enter()
.append('div')
.attr('class', 'form-fields-container ' + (klass || ''))
.merge(container);
var fields = container.selectAll('.wrap-form-field')
.data(shown, function(d) { return d.id; });
fields.exit()
.remove();
// Enter
var enter = fields.enter()
.append('div')
.attr('class', function(d) { return 'wrap-form-field wrap-form-field-' + d.id; });
// Update
fields = fields
.merge(enter);
fields
.order()
.each(function(d) {
d3.select(this)
.call(d.render);
});
notShown = notShown.map(function(field) {
return {
title: field.label(),
value: field.label(),
field: field
};
});
var more = selection.selectAll('.more-fields')
.data((notShown.length > 0) ? [0] : []);
more.exit()
.remove();
more = more.enter()
.append('div')
.attr('class', 'more-fields')
.append('label')
.text(t('inspector.add_fields'))
.merge(more);
var input = more.selectAll('.value')
.data([0]);
input.exit()
.remove();
input = input.enter()
.append('input')
.attr('class', 'value')
.attr('type', 'text')
.call(utilNoAuto)
.merge(input);
input
.call(utilGetSetValue, '')
.attr('placeholder', function() {
var placeholder = [];
for (var field in notShown) {
placeholder.push(notShown[field].title);
}
return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
})
.call(d3combobox()
.container(context.container())
.data(notShown)
.minItems(1)
.on('accept', function (d) {
var field = d.field;
field.show = true;
render(selection);
if (field.type !== 'semiCombo' && field.type !== 'multiCombo') {
field.focus();
}
})
);
}
formFields.fieldsArr = function(_) {
if (!arguments.length) return fieldsArr;
fieldsArr = _;
return formFields;
};
return formFields;
}
+4
View File
@@ -2,8 +2,11 @@ export { uiInit } from './init';
export { uiAccount } from './account';
export { uiAttribution } from './attribution';
export { uiBackground } from './background';
export { uiChangesetEditor } from './changeset_editor';
export { uiCmd } from './cmd';
export { uiCommit } from './commit';
export { uiCommitChanges } from './commit_changes';
export { uiCommitWarnings } from './commit_warnings';
export { uiConfirm } from './confirm';
export { uiConflicts } from './conflicts';
export { uiContributors } from './contributors';
@@ -15,6 +18,7 @@ export { uiFeatureInfo } from './feature_info';
export { uiFeatureList } from './feature_list';
export { uiField } from './field';
export { uiFlash } from './flash';
export { uiFormFields } from './form_fields';
export { uiFullScreen } from './full_screen';
export { uiGeolocate } from './geolocate';
export { uiHelp } from './help';
+22
View File
@@ -1,4 +1,5 @@
import * as d3 from 'd3';
import _ from 'lodash';
import { t, textDirection } from '../../util/locale';
import { localize } from './helper';
@@ -88,6 +89,13 @@ export function uiIntro(context) {
var curtain = uiCurtain();
selection.call(curtain);
// store that the user started the walkthrough..
context.storage('walkthrough_started', 'yes');
// restore previous walkthrough progress..
var storedProgress = context.storage('walkthrough_progress') || '';
var progress = storedProgress.split(';').filter(Boolean);
var chapters = chapterFlow.map(function(chapter, i) {
var s = chapterUi[chapter](context, curtain.reveal)
.on('done', function() {
@@ -102,11 +110,25 @@ export function uiIntro(context) {
d3.select('button.chapter-' + next)
.classed('next', true);
}
// store walkthrough progress..
progress.push(chapter);
context.storage('walkthrough_progress', _.uniq(progress).join(';'));
});
return s;
});
chapters[chapters.length - 1].on('startEditing', function() {
// store walkthrough progress..
progress.push('startEditing');
context.storage('walkthrough_progress', _.uniq(progress).join(';'));
// store if walkthrough is completed..
var incomplete = _.difference(chapterFlow, progress);
if (!incomplete.length) {
context.storage('walkthrough_completed', 'yes');
}
curtain.remove();
navwrap.remove();
d3.selectAll('#map .layer-background').style('opacity', opacity);
+12 -103
View File
@@ -1,18 +1,15 @@
import * as d3 from 'd3';
import { d3combobox } from '../lib/d3.combobox.js';
import { t } from '../util/locale';
import { modeBrowse } from '../modes';
import { uiDisclosure } from './disclosure';
import { uiField } from './field';
import {
utilGetSetValue,
utilNoAuto,
utilRebind
} from '../util';
import { uiFormFields } from './form_fields';
import { utilRebind } from '../util';
export function uiPresetEditor(context) {
var dispatch = d3.dispatch('change'),
formFields = uiFormFields(context),
expandedPreference = (context.storage('preset_fields.expanded') !== 'false'),
state,
fieldsArr,
@@ -80,106 +77,18 @@ export function uiPresetEditor(context) {
.tags(tags);
});
var shown = fieldsArr.filter(function(field) { return field.isShown(); }),
notShown = fieldsArr.filter(function(field) { return !field.isShown(); });
selection
.call(formFields.fieldsArr(fieldsArr), 'inspector-inner fillL3');
var form = selection.selectAll('.preset-form')
.data([0]);
form = form.enter()
.append('div')
.attr('class', 'preset-form inspector-inner fillL3')
.merge(form);
var fields = form.selectAll('.wrap-form-field')
.data(shown, function(d) { return d.id; });
fields.exit()
.remove();
// Enter
var enter = fields.enter()
.append('div')
.attr('class', function(d) { return 'wrap-form-field wrap-form-field-' + d.id; });
// Update
fields = fields
.merge(enter);
fields
.order()
.each(function(d) {
d3.select(this)
.call(d.render)
.selectAll('input')
.on('keydown', function() {
// if user presses enter, and combobox is not active, accept edits..
if (d3.event.keyCode === 13 && d3.select('.combobox').empty()) {
context.enter(modeBrowse(context));
}
});
});
notShown = notShown.map(function(field) {
return {
title: field.label(),
value: field.label(),
field: field
};
});
var more = selection.selectAll('.more-fields')
.data((notShown.length > 0) ? [0] : []);
more.exit()
.remove();
more = more.enter()
.append('div')
.attr('class', 'more-fields')
.append('label')
.text(t('inspector.add_fields'))
.merge(more);
var input = more.selectAll('.value')
.data([0]);
input.exit()
.remove();
input = input.enter()
.append('input')
.attr('class', 'value')
.attr('type', 'text')
.call(utilNoAuto)
.merge(input);
input
.call(utilGetSetValue, '')
.attr('placeholder', function() {
var placeholder = [];
for (var field in notShown) {
placeholder.push(notShown[field].title);
selection.selectAll('.wrap-form-field input')
.on('keydown', function() {
// if user presses enter, and combobox is not active, accept edits..
if (d3.event.keyCode === 13 && d3.select('.combobox').empty()) {
context.enter(modeBrowse(context));
}
return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
})
.call(d3combobox()
.container(context.container())
.data(notShown)
.minItems(1)
.on('accept', function (d) {
var field = d.field;
field.show = true;
render(selection);
field.focus();
})
);
});
}
+6 -1
View File
@@ -175,7 +175,12 @@ export function uiRawTagEditor(context) {
function isReadOnly(d) {
return readOnlyTags.indexOf(d.key) !== -1;
for (var i = 0; i < readOnlyTags.length; i++) {
if (d.key.match(readOnlyTags[i]) !== null) {
return true;
}
}
return false;
}
+38 -15
View File
@@ -9,8 +9,8 @@ import { svgIcon } from '../svg/index';
export function uiTagReference(tag) {
var taginfo = services.taginfo,
tagReference = {},
button,
body,
button = d3.select(null),
body = d3.select(null),
loaded,
showing;
@@ -46,7 +46,8 @@ export function uiTagReference(tag) {
function load(param) {
if (!taginfo) return;
button.classed('tag-reference-loading', true);
button
.classed('tag-reference-loading', true);
taginfo.docs(param, function show(err, data) {
var docs;
@@ -56,22 +57,23 @@ export function uiTagReference(tag) {
body.html('');
if (!docs || !docs.title) {
if (param.hasOwnProperty('value')) {
load(_.omit(param, 'value')); // retry with key only
} else {
body.append('p').text(t('inspector.no_documentation_key'));
body
.append('p')
.attr('class', 'tag-reference-description')
.text(t('inspector.no_documentation_key'));
done();
}
return;
}
if (docs.image && docs.image.thumb_url_prefix) {
body
.append('img')
.attr('class', 'wiki-image')
.attr('class', 'tag-reference-wiki-image')
.attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
.on('load', function() { done(); })
.on('error', function() { d3.select(this).remove(); done(); });
@@ -81,16 +83,31 @@ export function uiTagReference(tag) {
body
.append('p')
.attr('class', 'tag-reference-description')
.text(docs.description || t('inspector.documentation_redirect'));
body
.append('a')
.attr('class', 'tag-reference-link')
.attr('target', '_blank')
.attr('tabindex', -1)
.attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
.call(svgIcon('#icon-out-link', 'inline'))
.append('span')
.text(t('inspector.reference'));
// Add link to info about "good changeset comments" - #2923
if (param.key === 'comment') {
body
.append('a')
.attr('class', 'tag-reference-comment-link')
.attr('target', '_blank')
.attr('tabindex', -1)
.call(svgIcon('#icon-out-link', 'inline'))
.attr('href', t('commit.about_changeset_comments_link'))
.append('span')
.text(t('commit.about_changeset_comments'));
}
});
}
@@ -98,9 +115,12 @@ export function uiTagReference(tag) {
function done() {
loaded = true;
button.classed('tag-reference-loading', false);
button
.classed('tag-reference-loading', false);
body.transition()
body
.classed('expanded', true)
.transition()
.duration(200)
.style('max-height', '200px')
.style('opacity', '1');
@@ -109,12 +129,15 @@ export function uiTagReference(tag) {
}
function hide(selection) {
selection = selection || body.transition().duration(200);
selection
function hide() {
body
.transition()
.duration(200)
.style('max-height', '0px')
.style('opacity', '0');
.style('opacity', '0')
.on('end', function () {
body.classed('expanded', false);
});
showing = false;
}
@@ -158,7 +181,7 @@ export function uiTagReference(tag) {
.merge(body);
if (showing === false) {
hide(body);
hide();
}
};