Merge remote-tracking branch 'systemed/master' into intro
Conflicts: build.js data/locales.js
@@ -72,6 +72,21 @@ Transiflex, will automatically detect the change.
|
||||
Use `make` to build the translations with the local changes.
|
||||
`make translate` can be used to pull the latest translations from Transifex.
|
||||
|
||||
## Contributing Documentation
|
||||
|
||||
Documentation is maintained as a series of [Markdown](http://daringfireball.net/projects/markdown/)
|
||||
documents in the `data/doc/` path. The first line of each page of documentation
|
||||
should be of the form
|
||||
|
||||
# GPS
|
||||
|
||||
This will be used for navigation and as its title in iD. Documentation is
|
||||
shown in alphabetical order, so most documentation is prefixed with `02-` and
|
||||
so on in order to keep it in a certain order.
|
||||
|
||||
To add a new page of documentation, simply create a new Markdown file in
|
||||
`data/doc` in the same format as the rest.
|
||||
|
||||
## Javascript
|
||||
|
||||
We use the [Airbnb style for Javascript](https://github.com/airbnb/javascript) with
|
||||
|
||||
@@ -9,7 +9,7 @@ all: \
|
||||
iD.js \
|
||||
iD.min.js
|
||||
|
||||
DATA_FILES = $(shell find data -type f -name '*.json')
|
||||
DATA_FILES = $(shell find data -type f -name '*.json' -o -name '*.md')
|
||||
data/data.js: $(DATA_FILES)
|
||||
node build.js
|
||||
|
||||
@@ -18,6 +18,7 @@ data/data.js: $(DATA_FILES)
|
||||
js/lib/d3.v3.js \
|
||||
js/lib/d3.combobox.js \
|
||||
js/lib/d3.geo.tile.js \
|
||||
js/lib/d3.jsonp.js \
|
||||
js/lib/d3.keybinding.js \
|
||||
js/lib/d3.one.js \
|
||||
js/lib/d3.size.js \
|
||||
|
||||
@@ -2,13 +2,18 @@ var fs = require('fs'),
|
||||
path = require('path'),
|
||||
glob = require('glob'),
|
||||
YAML = require('js-yaml'),
|
||||
marked = require('marked'),
|
||||
_ = require('./js/lib/lodash'),
|
||||
jsonschema = require('jsonschema'),
|
||||
fieldSchema = require('./data/presets/schema/field.json'),
|
||||
presetSchema = require('./data/presets/schema/preset.json');
|
||||
|
||||
function readtxt(f) {
|
||||
return fs.readFileSync(f, 'utf8');
|
||||
}
|
||||
|
||||
function read(f) {
|
||||
return JSON.parse(fs.readFileSync(f));
|
||||
return JSON.parse(readtxt(f));
|
||||
}
|
||||
|
||||
function r(f) {
|
||||
@@ -19,6 +24,10 @@ function rp(f) {
|
||||
return r('presets/' + f);
|
||||
}
|
||||
|
||||
function stringify(o) {
|
||||
return JSON.stringify(o, null, 4);
|
||||
}
|
||||
|
||||
function validate(file, instance, schema) {
|
||||
var result = jsonschema.validate(instance, schema);
|
||||
if (result.length) {
|
||||
@@ -39,59 +48,81 @@ var translations = {
|
||||
presets: {}
|
||||
};
|
||||
|
||||
var fields = {};
|
||||
glob.sync(__dirname + '/data/presets/fields/*.json').forEach(function(file) {
|
||||
var field = read(file),
|
||||
id = path.basename(file, '.json');
|
||||
function generateDocumentation() {
|
||||
var docs = [];
|
||||
glob.sync(__dirname + '/data/doc/*.md').forEach(function(file) {
|
||||
var text = readtxt(file),
|
||||
title = text.split('\n')[0]
|
||||
.replace('#', '').trim();
|
||||
docs.push({
|
||||
html: marked(text.split('\n').slice(1).join('\n')),
|
||||
title: title
|
||||
});
|
||||
});
|
||||
fs.writeFileSync('data/doc.json', stringify(docs));
|
||||
}
|
||||
|
||||
validate(file, field, fieldSchema);
|
||||
function generateFields() {
|
||||
var fields = {};
|
||||
glob.sync(__dirname + '/data/presets/fields/*.json').forEach(function(file) {
|
||||
var field = read(file),
|
||||
id = path.basename(file, '.json');
|
||||
|
||||
translations.fields[id] = {label: field.label};
|
||||
if (field.strings) {
|
||||
for (var i in field.strings) {
|
||||
translations.fields[id][i] = field.strings[i];
|
||||
validate(file, field, fieldSchema);
|
||||
|
||||
translations.fields[id] = {label: field.label};
|
||||
if (field.strings) {
|
||||
for (var i in field.strings) {
|
||||
translations.fields[id][i] = field.strings[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fields[id] = field;
|
||||
});
|
||||
fs.writeFileSync('data/presets/fields.json', JSON.stringify(fields, null, 4));
|
||||
fields[id] = field;
|
||||
});
|
||||
fs.writeFileSync('data/presets/fields.json', stringify(fields));
|
||||
}
|
||||
|
||||
var presets = {};
|
||||
glob.sync(__dirname + '/data/presets/presets/**/*.json').forEach(function(file) {
|
||||
var preset = read(file),
|
||||
id = file.match(/presets\/presets\/([^.]*)\.json/)[1];
|
||||
function generatePresets() {
|
||||
var presets = {};
|
||||
glob.sync(__dirname + '/data/presets/presets/**/*.json').forEach(function(file) {
|
||||
var preset = read(file),
|
||||
id = file.match(/presets\/presets\/([^.]*)\.json/)[1];
|
||||
|
||||
validate(file, preset, presetSchema);
|
||||
validate(file, preset, presetSchema);
|
||||
|
||||
translations.presets[id] = {
|
||||
name: preset.name,
|
||||
terms: (preset.terms || []).join(',')
|
||||
};
|
||||
translations.presets[id] = {
|
||||
name: preset.name,
|
||||
terms: (preset.terms || []).join(',')
|
||||
};
|
||||
|
||||
presets[id] = preset;
|
||||
});
|
||||
fs.writeFileSync('data/presets/presets.json', JSON.stringify(presets, null, 4));
|
||||
presets[id] = preset;
|
||||
});
|
||||
fs.writeFileSync('data/presets/presets.json', stringify(presets));
|
||||
fs.writeFileSync('data/presets.yaml', YAML.dump({en: {presets: translations}}));
|
||||
}
|
||||
|
||||
fs.writeFileSync('data/presets.yaml', YAML.dump({en: {presets: translations}}));
|
||||
generateDocumentation();
|
||||
generateFields();
|
||||
generatePresets();
|
||||
|
||||
fs.writeFileSync('data/data.js', 'iD.data = ' + JSON.stringify({
|
||||
fs.writeFileSync('data/data.js', 'iD.data = ' + stringify({
|
||||
deprecated: r('deprecated.json'),
|
||||
discarded: r('discarded.json'),
|
||||
keys: r('keys.json'),
|
||||
imagery: r('imagery.json'),
|
||||
doc: r('doc.json'),
|
||||
presets: {
|
||||
presets: rp('presets.json'),
|
||||
defaults: rp('defaults.json'),
|
||||
categories: rp('categories.json'),
|
||||
fields: rp('fields.json')
|
||||
}
|
||||
}, null, 4) + ';');
|
||||
}) + ';');
|
||||
|
||||
// Push changes from data/core.yaml into data/locales.js
|
||||
var core = YAML.load(fs.readFileSync('data/core.yaml', 'utf8'));
|
||||
var presets = YAML.load(fs.readFileSync('data/presets.yaml', 'utf8'));
|
||||
var intro = YAML.load(fs.readFileSync('data/intro.yaml', 'utf8'));
|
||||
var en = _.merge(_.merge(core, presets), intro);
|
||||
var out = 'locale.en = ' + JSON.stringify(en.en, null, 4) + ';';
|
||||
var out = 'locale.en = ' + stringify(en.en) + ';';
|
||||
fs.writeFileSync('data/locales.js', fs.readFileSync('data/locales.js', 'utf8').replace(/locale.en =[^;]*;/, out));
|
||||
|
||||
@@ -70,7 +70,6 @@
|
||||
<script src='js/id/ui/save.js'></script>
|
||||
<script src='js/id/ui/tag_reference.js'></script>
|
||||
<script src='js/id/ui/tail.js'></script>
|
||||
<script src='js/id/ui/key_reference.js'></script>
|
||||
|
||||
<script src='js/id/actions.js'></script>
|
||||
<script src="js/id/actions/add_midpoint.js"></script>
|
||||
|
||||
@@ -62,7 +62,7 @@ h2 {
|
||||
font-size: 25px;
|
||||
line-height: 1.25;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
h3:last-child,
|
||||
@@ -71,11 +71,9 @@ h4:last-child { margin-bottom: 0;}
|
||||
|
||||
h3 {
|
||||
font-size: 16px;
|
||||
line-height: 1.3333;
|
||||
line-height: 1.25;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@@ -96,10 +94,15 @@ h5 {
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 12px;
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
p:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: italic;
|
||||
}
|
||||
@@ -147,6 +150,7 @@ input[type=email] {
|
||||
background-color: white;
|
||||
border:1px solid #ccc;
|
||||
padding:5px 10px;
|
||||
height:30px;
|
||||
width: 100%;
|
||||
border-radius:4px;
|
||||
-webkit-transition: all 100ms;
|
||||
@@ -159,11 +163,6 @@ input:focus {
|
||||
background-color: #F1F1F1;
|
||||
}
|
||||
|
||||
input[type=text] {
|
||||
padding:5px 10px;
|
||||
height:30px;
|
||||
}
|
||||
|
||||
input.major {
|
||||
width: 100%;
|
||||
padding:5px 10px;
|
||||
@@ -258,6 +257,11 @@ ul.link-list li:last-child {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.fillL3 {
|
||||
background: #f1f1f1;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.fillD {
|
||||
background:rgba(0,0,0,.8);
|
||||
color: #6C6C6C;
|
||||
@@ -310,7 +314,6 @@ a.hide {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
|
||||
/* Buttons */
|
||||
|
||||
button {
|
||||
@@ -393,10 +396,10 @@ button.action:hover {
|
||||
background: #597BE7;
|
||||
}
|
||||
|
||||
button.delete {
|
||||
button.cancel {
|
||||
background-color: #ff7070;
|
||||
}
|
||||
button.delete:hover {
|
||||
button.cancel:hover {
|
||||
background-color: #ef5454;
|
||||
}
|
||||
|
||||
@@ -500,8 +503,11 @@ button[disabled] .label {
|
||||
.icon.warning { background-position: -380px 0px;}
|
||||
.icon.back { background-position: -420px 0px;}
|
||||
.icon.forward { background-position: -440px 0px;}
|
||||
.icon.help { background-position: -460px 0px;}
|
||||
|
||||
.icon.inspect.light { background-position: -220px -20px;}
|
||||
.icon.geocode.light { background-position: -280px -20px;}
|
||||
.icon.help.light { background-position: -460px -20px;}
|
||||
|
||||
.fillD .icon.avatar { background-position: -320px -20px;}
|
||||
.fillD .icon.nearby { background-position: -340px -20px;}
|
||||
@@ -513,7 +519,6 @@ button[disabled] .icon.add-area { background-position: -60px -40px;}
|
||||
button.disabled .icon.undo { background-position: -80px -40px;}
|
||||
button.disabled .icon.redo { background-position: -100px -40px;}
|
||||
button[disabled] .apply.icon { background-position: -120px -40px;}
|
||||
button[disabled] .save.icon { background-position: -140px -40px;}
|
||||
button[disabled] .close.icon { background-position: -160px -40px;}
|
||||
button[disabled] .delete.icon { background-position: -180px -40px;}
|
||||
button[disabled] .icon.remove { background-position: -200px -40px;}
|
||||
@@ -569,18 +574,22 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
|
||||
/* Header for modals / panes
|
||||
------------------------------------------------------- */
|
||||
|
||||
.header {
|
||||
border-bottom: 1px solid #ccc;
|
||||
z-index: 2;
|
||||
height: 60px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header h3 {
|
||||
margin-right: 40px;
|
||||
margin-bottom: 0;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modal > button,
|
||||
@@ -593,10 +602,11 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.modal > button {
|
||||
height: 61px;
|
||||
height: 59px;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
@@ -627,10 +637,6 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
|
||||
top: 120px;
|
||||
}
|
||||
|
||||
.inspector-body::-webkit-scrollbar {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.inspector-inner {
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
@@ -639,15 +645,11 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
|
||||
.inspector-wrap .header button.preset-reset {
|
||||
border-right: 1px solid #CCC;
|
||||
position: relative;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.inspector-wrap .header button.preset-reset > div {
|
||||
height: 100%;
|
||||
padding: 20px 0;
|
||||
-webkit-transition: opacity 200ms;
|
||||
-moz-transition: opacity 200ms;
|
||||
transition: opacity 200ms;
|
||||
}
|
||||
|
||||
.inspector-wrap .header button.preset-reset .col12:last-child {
|
||||
@@ -669,12 +671,6 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.pane:last-child .header h3 {
|
||||
position: absolute;
|
||||
left: 60px;
|
||||
right: 40px;
|
||||
}
|
||||
|
||||
.inspector-toggle {
|
||||
color:#fff;
|
||||
width: 100%;
|
||||
@@ -715,25 +711,6 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
|
||||
background: #ececec;
|
||||
}
|
||||
|
||||
.grid-entry:hover .preset-help {
|
||||
display: block;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.grid-entry .preset-help {
|
||||
display: none;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
background: rgba(0,0,0,.5);
|
||||
}
|
||||
|
||||
.grid-entry .preset-help:hover {
|
||||
background: rgba(0,0,0,.9);
|
||||
}
|
||||
|
||||
.grid-entry > .icon {
|
||||
position: absolute;
|
||||
top: 30px;left: 0px; right: 0px;
|
||||
@@ -814,23 +791,24 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
|
||||
}
|
||||
|
||||
.subgrid {
|
||||
width: -webkit-calc(100% - 10px);
|
||||
width: calc(100% - 10px);
|
||||
width: 100%;
|
||||
width: -webkit-calc(100% + 10px);
|
||||
width: calc(100% + 10px);
|
||||
margin-left: -10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.subgrid .preset-grid {
|
||||
background: #eee;
|
||||
padding: 10px 0px 0px 10px;
|
||||
border: 1px solid #CCC;
|
||||
margin-top: 0px;
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.subgrid .arrow {
|
||||
border: solid rgba(0, 0, 0, 0);
|
||||
border-width: 10px;
|
||||
border-bottom-color: #eee;
|
||||
border-bottom-color: #CCC;
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-left: 33.3333%;
|
||||
@@ -861,6 +839,25 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.grid-entry:hover .tag-reference-button {
|
||||
opacity: 1;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.grid-entry .tag-reference-button {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 20px;
|
||||
height: 30px;
|
||||
background: rgba(0,0,0,.5);
|
||||
}
|
||||
|
||||
.grid-entry .tag-reference-button:hover {
|
||||
background: rgba(0,0,0,.9);
|
||||
}
|
||||
|
||||
/* Preset icon colors */
|
||||
|
||||
.inspector-body-line .icon.feature-marker-stroked {
|
||||
@@ -900,69 +897,104 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
|
||||
|
||||
/* preset form basics */
|
||||
|
||||
.preset-field.inspector-inner {
|
||||
padding-bottom: 0;
|
||||
.tag-wrap .preset-icon-wrap {
|
||||
border-bottom: 1px solid #CCC;
|
||||
}
|
||||
|
||||
.tag-wrap .grid-button-wrap {
|
||||
padding: 0;
|
||||
height: 110px;
|
||||
}
|
||||
|
||||
.tag-wrap .grid-button-wrap .grid-entry {
|
||||
border-top: 0;
|
||||
background: #eef0ff;
|
||||
}
|
||||
|
||||
.tag-wrap .grid-button-wrap .grid-entry .label {
|
||||
background: #eef0ff;
|
||||
}
|
||||
|
||||
.preset-field h4 .modified-icon {
|
||||
opacity: 0.2;
|
||||
display: none;
|
||||
pointer-events: all;
|
||||
}
|
||||
.preset-field h4 .modified-icon:hover {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.preset-field.modified h4 .modified-icon {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.preset-field h4[for*="input-"] {
|
||||
border: 1px solid #cfcfcf;
|
||||
padding: 5px 10px;
|
||||
background: #f6f6f6;
|
||||
.tag-wrap .preset-icon-wrap::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
right: 20px;
|
||||
height: 0;
|
||||
width: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
border: solid rgba(0, 0, 0, 0);
|
||||
border-width: 10px;
|
||||
border-bottom-color: #CCC;
|
||||
}
|
||||
|
||||
.tag-wrap .preset-icon-wrap div {
|
||||
height: 80px;
|
||||
width: 33.3333%;
|
||||
width: -webkit-calc(33.3333% - 10px);
|
||||
width: calc(33.3333% - 10px);
|
||||
margin: auto;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #CCC;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tag-wrap .preset-icon-wrap .preset-icon {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.tag-wrap .preset-icon-wrap .preset-icon.line {
|
||||
top: 15px;
|
||||
}
|
||||
|
||||
.inspector-preset .form-field {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
position: relative;
|
||||
font-weight: bold;
|
||||
border: 1px solid #cfcfcf;
|
||||
padding: 5px 0px 5px 10px;
|
||||
background: #f6f6f6;
|
||||
display: block;
|
||||
border-radius: 4px 4px 0 0;
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.preset-field h4 + input,
|
||||
h4 + .input-wrap-position input,
|
||||
h4 + .preset-input input:first-child {
|
||||
padding-top: 35px;
|
||||
height: 60px;
|
||||
.form-label button {
|
||||
pointer-events: all;
|
||||
height: 29px;
|
||||
margin-top: -5px;
|
||||
border-left: 1px solid #CCC;
|
||||
border-radius: 0;
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.preset-field h4 + textarea {
|
||||
padding-top: 35px;
|
||||
height: 100px;
|
||||
.form-label .modified-icon {
|
||||
border-right: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.preset-field h4[for="input-building:levels"],
|
||||
.preset-field h4[for="input-ele"],
|
||||
.preset-field.checkselect h4 {
|
||||
right: 50%;
|
||||
.modified .form-label .modified-icon {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.preset-field-name h4 + input {
|
||||
padding-top: 35px;
|
||||
height: 70px;
|
||||
.form-label button.tag-reference-button {
|
||||
border-top-right-radius: 3px;
|
||||
}
|
||||
|
||||
.form-field > input,
|
||||
.form-field > textarea,
|
||||
.form-field .preset-input-wrap {
|
||||
border: 1px solid #CCC;
|
||||
border-top: 0;
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
|
||||
.form-field textarea {
|
||||
height: 65px;
|
||||
}
|
||||
|
||||
.form-field-levels,
|
||||
.form-field-elevation,
|
||||
.form-field.checkselect {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.form-field-name input {
|
||||
height: 35px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -989,21 +1021,16 @@ button.preset-add-field {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.view-on-osm {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
/* preset form numbers */
|
||||
|
||||
input[type=number] {
|
||||
position: relative;
|
||||
width: 50%;
|
||||
padding-right: 65px;
|
||||
}
|
||||
|
||||
.spin-control {
|
||||
width: 60px;
|
||||
height: 30px;
|
||||
height: 29px;
|
||||
border-left: 1px solid #CCC;
|
||||
display: inline-block;
|
||||
margin-left: -60px;
|
||||
@@ -1016,13 +1043,14 @@ input[type=number] {
|
||||
float: left;
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
border: 1px solid #CCC;
|
||||
border-left: 1px solid #CCC;
|
||||
border-right: 1px solid #CCC;
|
||||
border-radius: 0;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.spin-control button.descend {
|
||||
border-bottom-right-radius: 4px;
|
||||
.spin-control button.decrement {
|
||||
border-bottom-right-radius: 3px;
|
||||
}
|
||||
|
||||
.spin-control button.decrement::after,
|
||||
@@ -1048,14 +1076,11 @@ input[type=number] {
|
||||
|
||||
/* preset form checkbox */
|
||||
|
||||
.checkselect label {
|
||||
.checkselect label:last-of-type {
|
||||
display: block;
|
||||
padding: 35px 5px 5px 5px;
|
||||
border-radius: 4px;
|
||||
margin-right: 50%;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
color: #999;
|
||||
border: 1px solid #CCC;
|
||||
}
|
||||
|
||||
.checkselect label:hover {
|
||||
@@ -1081,11 +1106,8 @@ input[type=number] {
|
||||
|
||||
.radio-wrap {
|
||||
display: block;
|
||||
padding: 30px 0 0 0;
|
||||
border-radius: 4px;
|
||||
box-sizing: border-box;
|
||||
color: #999;
|
||||
border: 1px solid #CCC;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -1106,25 +1128,29 @@ input[type=number] {
|
||||
|
||||
/* Preset form address */
|
||||
|
||||
.preset-field .addr-housename {
|
||||
border-bottom: none;
|
||||
border-radius: 4px 4px 0 0;
|
||||
.form-field .addr-housename {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.preset-field .addr-number {
|
||||
.form-field .addr-number {
|
||||
width: 20%;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.preset-field .addr-street {
|
||||
.form-field .addr-street {
|
||||
width: 80%;
|
||||
border-radius: 0;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.preset-field .addr-city {
|
||||
.form-field .addr-city {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-bottom: none;
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
|
||||
@@ -1209,7 +1235,7 @@ div.combobox {
|
||||
.tag-row {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
height: 30px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.tag-row input {
|
||||
@@ -1228,7 +1254,6 @@ div.combobox {
|
||||
border-right: 1px solid #CCC;
|
||||
}
|
||||
|
||||
|
||||
.tag-row:first-child input.key {
|
||||
border-top: 1px solid #CCC;
|
||||
border-top-left-radius: 4px;
|
||||
@@ -1255,6 +1280,10 @@ div.combobox {
|
||||
left: -20px
|
||||
}
|
||||
|
||||
.tag-row div.tag-help {
|
||||
display: hidden;
|
||||
}
|
||||
|
||||
.tag-row:hover input.value,
|
||||
.tag-row:hover input.key {
|
||||
border-radius: 0;
|
||||
@@ -1282,6 +1311,20 @@ div.combobox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Tag reference */
|
||||
|
||||
.tag-help {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
img.wiki-image {
|
||||
float: left;
|
||||
max-width: 33.3333%;
|
||||
margin-right: 20px;
|
||||
max-height: 200px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Map Controls */
|
||||
|
||||
.map-control {
|
||||
@@ -1523,10 +1566,68 @@ div.combobox {
|
||||
}
|
||||
|
||||
.geolocate-control button {
|
||||
}
|
||||
|
||||
/* Help */
|
||||
|
||||
.help-control {
|
||||
top: 270px;
|
||||
}
|
||||
|
||||
.help-control button {
|
||||
border-radius: 0 0 4px 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.help-wrap {
|
||||
position: absolute;
|
||||
top:60px;
|
||||
bottom: 30px;
|
||||
padding: 20px 20px 20px 50px;
|
||||
left: 0;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.help-wrap p {
|
||||
font-size: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.help-wrap .left-content .body p code {
|
||||
padding:2px 4px;
|
||||
background:#eee;
|
||||
}
|
||||
|
||||
.help-wrap .toc {
|
||||
/* This is two columns, 41.66666 x .4 = 16.6666 */
|
||||
width:40%;
|
||||
float:right;
|
||||
margin-left: 20px;
|
||||
margin-bottom: 20px;
|
||||
padding-left: 5px
|
||||
}
|
||||
|
||||
.help-wrap .toc li a {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
border: 1px solid #CCC;
|
||||
border-bottom: 0px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.help-wrap .toc li a.selected {
|
||||
background: #eef0ff;
|
||||
}
|
||||
|
||||
.help-wrap .toc li:first-child a {
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
|
||||
.help-wrap .toc li:last-child a {
|
||||
border-bottom: 1px solid #CCC;
|
||||
border-radius: 0 0 4px 4px
|
||||
}
|
||||
|
||||
/* Map
|
||||
------------------------------------------------------- */
|
||||
|
||||
@@ -1597,6 +1698,20 @@ div.combobox {
|
||||
color:#fff;
|
||||
}
|
||||
|
||||
/* Attribution overlay */
|
||||
.attribution {
|
||||
position: absolute;
|
||||
bottom: 35px;
|
||||
right:10px;
|
||||
color:#888;
|
||||
font-size:10px;
|
||||
}
|
||||
|
||||
.source-image {
|
||||
height:20px;
|
||||
vertical-align:top;
|
||||
}
|
||||
|
||||
.user-list a:not(:last-child):after {
|
||||
content: ', ';
|
||||
}
|
||||
@@ -1798,7 +1913,7 @@ div.typeahead a:first-child {
|
||||
------------------------------------------------------- */
|
||||
|
||||
.modal a.success-action {
|
||||
height: 180px;
|
||||
height: 170px;
|
||||
border-bottom: 1px solid #CCC;
|
||||
text-align: center;
|
||||
-webkit-transition: all 200ms;
|
||||
@@ -1820,7 +1935,7 @@ a.success-action:before {
|
||||
height: 100px;
|
||||
width: 100px;
|
||||
margin: auto;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 10px;
|
||||
background:transparent url(../img/sprite.png) no-repeat 0px -220px;
|
||||
}
|
||||
|
||||
@@ -2091,13 +2206,24 @@ a.success-action.twitter:before {
|
||||
@media only screen and (max-height: 840px) {
|
||||
}
|
||||
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
|
||||
only screen and (-o-min-device-pixel-ratio: 3/2),
|
||||
only screen and (min--moz-device-pixel-ratio: 1.5),
|
||||
only screen and (min-device-pixel-ratio: 1.5) {
|
||||
.map-control .icon,
|
||||
.button-wrap .icon {
|
||||
background-image: url(../img/sprite2x.png);
|
||||
background-size: 500px 320px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scrollbars
|
||||
----------------------------------------------------- */
|
||||
::-webkit-scrollbar {
|
||||
height: 20px;
|
||||
overflow: visible;
|
||||
width: 10px;
|
||||
background: #EBEBEB;
|
||||
background: white;
|
||||
border-left: 1px solid #DDD;
|
||||
}
|
||||
::-webkit-scrollbar-button {
|
||||
@@ -2114,10 +2240,8 @@ a.success-action.twitter:before {
|
||||
}
|
||||
::-webkit-scrollbar-track:hover {
|
||||
background-color: rgba(0,0,0,.05);
|
||||
box-shadow: inset 1px 0 0 rgba(0,0,0,.1);
|
||||
}
|
||||
::-webkit-scrollbar-track:horizontal:hover {
|
||||
box-shadow: inset 0 1px 0 rgba(0,0,0,.1)
|
||||
}
|
||||
::-webkit-scrollbar-track:active {
|
||||
background-color: rgba(0,0,0,.05);
|
||||
|
||||
@@ -856,11 +856,11 @@ text.point {
|
||||
cursor: url(../img/cursor-select-remove.png), pointer;
|
||||
}
|
||||
|
||||
.point:active,
|
||||
.vertex:active,
|
||||
.line:active,
|
||||
.area:active,
|
||||
.midpoint:active,
|
||||
#map .point:active,
|
||||
#map .vertex:active,
|
||||
#map .line:active,
|
||||
#map .area:active,
|
||||
#map .midpoint:active,
|
||||
.mode-select .selected {
|
||||
cursor: url(../img/cursor-select-acting.png), pointer;
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ en:
|
||||
nothing_to_redo: Nothing to redo.
|
||||
just_edited: "You just edited OpenStreetMap!"
|
||||
browser_notice: "This editor is supported in Firefox, Chrome, Safari, Opera, and Internet Explorer 9 and above. Please upgrade your browser or use Potlatch 2 to edit the map."
|
||||
view_on_osm: View on OSM
|
||||
view_on_osm: "View on OSM →"
|
||||
zoom_in_edit: zoom in to edit the map
|
||||
logout: logout
|
||||
report_a_bug: report a bug
|
||||
@@ -123,8 +123,8 @@ en:
|
||||
deleted: Deleted
|
||||
created: Created
|
||||
contributors:
|
||||
list: "Viewing contributions by {users}"
|
||||
truncated_list: "Viewing contributions by {users} and {count} others"
|
||||
list: "Contributed by {users}"
|
||||
truncated_list: "Contributed by {users} and {count} others"
|
||||
geocoder:
|
||||
title: Find a place
|
||||
placeholder: Find a place
|
||||
@@ -136,7 +136,7 @@ en:
|
||||
no_documentation_key: There is no documentation available for this key
|
||||
show_more: Show More
|
||||
new_tag: New tag
|
||||
view_on_osm: View on OSM
|
||||
view_on_osm: View on OSM →
|
||||
editing_feature: "Editing {feature}"
|
||||
additional: Additional tags
|
||||
choose: Select feature type
|
||||
@@ -150,7 +150,8 @@ en:
|
||||
fix_misalignment: Fix misalignment
|
||||
reset: reset
|
||||
restore:
|
||||
description: "You have unsaved changes from a previous editing session. Do you wish to restore these changes?"
|
||||
heading: You have unsaved changes
|
||||
description: "Do you wish to restore changes from a previous editing session?"
|
||||
restore: Restore
|
||||
reset: Reset
|
||||
save:
|
||||
@@ -167,6 +168,7 @@ en:
|
||||
start: Start Editing
|
||||
source_switch:
|
||||
live: live
|
||||
lose_changes: "You have unsaved changes. Switching the map server will discard them. Are you sure you want to switch servers?"
|
||||
dev: dev
|
||||
tag_reference:
|
||||
description: Description
|
||||
@@ -182,8 +184,8 @@ en:
|
||||
zoom:
|
||||
in: Zoom In
|
||||
out: Zoom Out
|
||||
imagery:
|
||||
provided_by: "Imagery provided by {source}"
|
||||
gpx:
|
||||
local_layer: "Local GPX file"
|
||||
drag_drop: "Drag and drop a .gpx file on the page"
|
||||
help:
|
||||
title: "Help"
|
||||
|
||||
@@ -12,7 +12,8 @@ iD.data = {
|
||||
path + 'data/presets/presets.json',
|
||||
path + 'data/presets/defaults.json',
|
||||
path + 'data/presets/categories.json',
|
||||
path + 'data/presets/fields.json'], d3.json, function (err, data) {
|
||||
path + 'data/presets/fields.json',
|
||||
path + 'data/doc.json'], d3.json, function (err, data) {
|
||||
|
||||
iD.data = {
|
||||
deprecated: data[0],
|
||||
@@ -24,7 +25,8 @@ iD.data = {
|
||||
defaults: data[5],
|
||||
categories: data[6],
|
||||
fields: data[7]
|
||||
}
|
||||
},
|
||||
doc: data[8]
|
||||
};
|
||||
|
||||
callback();
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
[
|
||||
{
|
||||
"html": "<p>This is an editor for <a href=\"http://www.openstreetmap.org/\">OpenStreetMap</a>, the\nfree and editable map of the world. You can use it to fix and update\ndata in your area, making an open-source and open-data map of the world\nbetter for everyone.</p>\n<p>Edits that you make on this map will be visible to everyone who uses\nOpenStreetMap. In order to make an edit, you'll need a\n<a href=\"https://www.openstreetmap.org/user/new\">free OpenStreetMap account</a>.</p>\n<p><a href=\"http://ideditor.com/\">iD Editor</a> is a collaborative project with <a href=\"https://github.com/systemed/iD\">source\ncode available on GitHub</a>.</p>\n",
|
||||
"title": "Help"
|
||||
},
|
||||
{
|
||||
"html": "<p>This editor is designed to work primarily online, and you're accessing\nit through a website right now.</p>\n<h3>Selecting Features</h3>\n<p>To select a map feature, like a road or point of interest, simply single-click\non it on the map. This will highlight the selected feature, show a panel of\ndetails, and also show a menu of things you can do with the feature.</p>\n<p>Multiple features can be selected by holding the 'Shift' key, clicking,\nand dragging on the map. This will select all features within the box\nthat's drawn, and you can do certain 'batch operations' on all features.</p>\n<h3>Saving Edits</h3>\n<p>When you create changes, like editing roads, buildings, and places, these are\nstored locally until you save them to the server. Don't worry if you make\na mistake - you can undo changes by clicking the undo button, and redo\nchanges by clicking the redo button.</p>\n<p>Click 'Save' to finish a group of edits - for instance, if you've completed\nan area of town and would like to start on a new area. You'll have a chance\nto review what you've done, and the editor supplies helpful suggestions\nand warnings if something doesn't seem right about the changes.</p>\n<p>Clicking 'Save' again, on the new dialog, will post the changes\nto <a href=\"http://www.openstreetmap.org/\">OpenStreetMap.org</a>, where they are visible\nto all other users and available for others to build and improve upon.</p>\n<p>If you can't finish your edits in one sitting, you can leave the editor\nwindow and come back (on the same browser and computer), and the\neditor application will offer to restore your work.</p>\n",
|
||||
"title": "Editing & Saving"
|
||||
},
|
||||
{
|
||||
"html": "<p>You can create, fix, and delete roads with this editor. Roads can be all\nkinds: paths, highways, trails, cycleways, and more - any often-crossed\nsegment should be mappable.</p>\n<h3>Selecting</h3>\n<p>Click on a road to select it. An outline should become visible, along\nwith a small tools menu on the map and a sidebar showing more information\nabout the road.</p>\n<h3>Modifying</h3>\n<p>Often you'll see roads that aren't aligned to the imagery behind them\nor a GPS track.</p>\n<p>First click on the road you want to change. This will highlight it and show\n'control points along it' that you can drag to better locations. If\nyou want to add new control points for more detail, double-click a part\nof the road without a point, and one will be added.</p>\n<p>If the road connects to another road, but doesn't properly connect on\nthe map, you can drag one of its control points onto the other road in\norder to join them. Having roads connect is important for the map\nand essential for providing driving directions.</p>\n<p>You can also click the 'Move' tool or type <code>M</code> to move the entire road at\none time, and then click again to save that movement.</p>\n<h3>Deleting</h3>\n<p>If a road is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the road could simply be newly built.</p>\n<p>You can delete a road by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.</p>\n<h3>Creating</h3>\n<p>Found somewhere there should be a road but there isn't? Click the 'Line'\nicon in the top-left of the editor or press the key '2' to start drawing\na line.</p>\n<p>Click on the start of the road on the map to start drawing. If the road\nconnects to another road, first, click on the place where they connect.</p>\n<p>Then click on points along the road so that it follows the right path, according\nto satellite imagery or GPS. When you're done drawing the road, double-click\nor press 'Return' or 'Enter' on your keyboard.</p>\n",
|
||||
"title": "Roads"
|
||||
},
|
||||
{
|
||||
"html": "<p>GPS data is the most trusted source of data for OpenStreetMap. This editor\nsupports local traces - <code>.gpx</code> files on your local computer. You can collect\nthis kind of GPS trace with a number of smartphone applications as well as\npersonal GPS hardware.</p>\n<p>For information on how to perform a GPS survey, read\n<a href=\"http://learnosm.org/en/beginner/using-gps/\">Surveying with a GPS</a>.</p>\n<p>To use a GPX track for mapping, drag and drop the GPX file onto the map map\neditor. If it's recognized, it will be added to the map as a bright green\nline. Click on the 'Background Settings' menu on the left side to enable,\ndisable, or zoom to this new GPX-powered layer.</p>\n<p>The GPX track isn't directly uploaded to OpenStreetMap - the best way to\nuse it is to draw on the map, using it as a guide for the new features that\nyou add.</p>\n",
|
||||
"title": "GPS"
|
||||
},
|
||||
{
|
||||
"html": "<p>Aerial imagery is an important resource for mapping. A combination of\nairplane flyovers, satellite views, and freely-compiled sources are available\nin the editor under the 'Background Settings' menu on the left.</p>\n<p>By default a <a href=\"http://www.bing.com/maps/\">Bing Maps</a> satellite layer is\npresented in the editor, but as you pan and zoom the map to new geographical\nareas, new sources will become available. Some countries, like the United\nStates, France, and Denmark have very high-resolution, high-quality imagery\navailable for smaller geographical coverages.</p>\n<p>Imagery is sometimes offset from the map data because of a mistake on the\nimagery provider's side - so if you see many roads shifted from the background,\ndon't immediately go to move them all. You can set an offset for imagery\nby clicking 'Fix alignment' at the bottom of the bottom of the Background\nSettings UI.</p>\n",
|
||||
"title": "Imagery"
|
||||
},
|
||||
{
|
||||
"html": "<p>Addresses are some of the most useful information for the map.</p>\n<p>Although addresses are often represented as parts of streets, in OpenStreetMap\nthey're recorded as attributes of buildings and places along streets.</p>\n<p>You can add address information to places mapped as building outlines as well\nas well as those mapped as single points. The optimal source of address\ndata is from an on-the-ground survey or personal knowledge - as with any\nother feature, copying from commercial sources like Google Maps is strictly\nforbidden.</p>\n",
|
||||
"title": "Addresses"
|
||||
},
|
||||
{
|
||||
"html": "<p>The inspector is the user interface element on the right-hand side of the\npage that appears when an element is selected and allows to edit its details.</p>\n<h3>Selecting a Preset</h3>\n<p>The inspector has two modes: the first allows you to pick a preset, or\npredetermined selection of forms and tags.</p>\n<p>Click the 'i' in the bottom-right-hand corner of a preset option to learn\nmore about it. Click a preset to choose it.</p>\n<h3>Using Forms and Editing Tags</h3>\n<p>The second allows you to edit the\nattributes of a map element using those forms and tags.</p>\n<p>Below the forms you see, you can click icons to add more easy-to-use forms,\nlike <a href=\"http://www.wikipedia.org/\">Wikipedia</a> information, wheelchair\naccess, and more.</p>\n<p>At the bottom of the inspector, click 'Additional tags' to add arbitrary\nother tags to the element. <a href=\"http://taginfo.openstreetmap.org/\">Taginfo</a> is a\ngreat resource for learn more about popular tag combinations.</p>\n<p>Changes you make in the inspector are automatically applied to the map.\nYou can undo them at any time by clicking the Undo button.</p>\n<h3>Closing the Inspector</h3>\n<p>You can close the inspector by either clicking the close button in the top-right,\npressing the 'Escape' key, or clicking on the map.</p>\n",
|
||||
"title": "Using the Inspector"
|
||||
},
|
||||
{
|
||||
"html": "<p>OpenStreetMap is the world's largest database of buildings. You can create\nand improve this database.</p>\n<h3>Selecting</h3>\n<p>You can select a building by clicking on its border. This will highlight the\nbuilding and open a small tools menu and a sidebar showing more information\nabout the building.</p>\n<h3>Modifying</h3>\n<p>Sometimes buildings are incorrectly placed or have incorrect tags.</p>\n<p>To move an entire building, select it, then click the 'Move' tool. Move your\nmouse to shift the building, and click when it's correctly placed.</p>\n<p>To fix the specific shape of a building, click and drag the points that form\nits border into better places.</p>\n<h3>Creating</h3>\n<p>One of the main questions around adding buildings to the map is that\nOpenStreetMap records buildings both as shapes and points. The rule of thumb\nis to <em>map a building as a shape whenever possible</em>, and map companies, homes,\namenities, and other things that operate out of buildings as points placed\nwithin the building shape.</p>\n<p>Start drawing a building as a shape by clicking the 'Area' button in the top\nleft of the interface, and end it either by pressing 'Return' on your keyboard\nor clicking on the first point drawn to close the shape.</p>\n<h3>Deleting</h3>\n<p>If a building is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the road could simply be newly built.</p>\n<p>You can delete a building by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.</p>\n",
|
||||
"title": "Buildings"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,13 @@
|
||||
# Help
|
||||
|
||||
This is an editor for [OpenStreetMap](http://www.openstreetmap.org/), the
|
||||
free and editable map of the world. You can use it to fix and update
|
||||
data in your area, making an open-source and open-data map of the world
|
||||
better for everyone.
|
||||
|
||||
Edits that you make on this map will be visible to everyone who uses
|
||||
OpenStreetMap. In order to make an edit, you'll need a
|
||||
[free OpenStreetMap account](https://www.openstreetmap.org/user/new).
|
||||
|
||||
[iD Editor](http://ideditor.com/) is a collaborative project with [source
|
||||
code available on GitHub](https://github.com/systemed/iD).
|
||||
@@ -0,0 +1,34 @@
|
||||
# Editing & Saving
|
||||
|
||||
This editor is designed to work primarily online, and you're accessing
|
||||
it through a website right now.
|
||||
|
||||
### Selecting Features
|
||||
|
||||
To select a map feature, like a road or point of interest, simply single-click
|
||||
on it on the map. This will highlight the selected feature, show a panel of
|
||||
details, and also show a menu of things you can do with the feature.
|
||||
|
||||
Multiple features can be selected by holding the 'Shift' key, clicking,
|
||||
and dragging on the map. This will select all features within the box
|
||||
that's drawn, and you can do certain 'batch operations' on all features.
|
||||
|
||||
### Saving Edits
|
||||
|
||||
When you create changes, like editing roads, buildings, and places, these are
|
||||
stored locally until you save them to the server. Don't worry if you make
|
||||
a mistake - you can undo changes by clicking the undo button, and redo
|
||||
changes by clicking the redo button.
|
||||
|
||||
Click 'Save' to finish a group of edits - for instance, if you've completed
|
||||
an area of town and would like to start on a new area. You'll have a chance
|
||||
to review what you've done, and the editor supplies helpful suggestions
|
||||
and warnings if something doesn't seem right about the changes.
|
||||
|
||||
Clicking 'Save' again, on the new dialog, will post the changes
|
||||
to [OpenStreetMap.org](http://www.openstreetmap.org/), where they are visible
|
||||
to all other users and available for others to build and improve upon.
|
||||
|
||||
If you can't finish your edits in one sitting, you can leave the editor
|
||||
window and come back (on the same browser and computer), and the
|
||||
editor application will offer to restore your work.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Roads
|
||||
|
||||
You can create, fix, and delete roads with this editor. Roads can be all
|
||||
kinds: paths, highways, trails, cycleways, and more - any often-crossed
|
||||
segment should be mappable.
|
||||
|
||||
### Selecting
|
||||
|
||||
Click on a road to select it. An outline should become visible, along
|
||||
with a small tools menu on the map and a sidebar showing more information
|
||||
about the road.
|
||||
|
||||
### Modifying
|
||||
|
||||
Often you'll see roads that aren't aligned to the imagery behind them
|
||||
or a GPS track.
|
||||
|
||||
First click on the road you want to change. This will highlight it and show
|
||||
'control points along it' that you can drag to better locations. If
|
||||
you want to add new control points for more detail, double-click a part
|
||||
of the road without a point, and one will be added.
|
||||
|
||||
If the road connects to another road, but doesn't properly connect on
|
||||
the map, you can drag one of its control points onto the other road in
|
||||
order to join them. Having roads connect is important for the map
|
||||
and essential for providing driving directions.
|
||||
|
||||
You can also click the 'Move' tool or type `M` to move the entire road at
|
||||
one time, and then click again to save that movement.
|
||||
|
||||
### Deleting
|
||||
|
||||
If a road is entirely incorrect - you can see that it doesn't exist in satellite
|
||||
imagery and ideally have confirmed locally that it's not present - you can delete
|
||||
it, which removes it from the map. Be cautious when deleting features -
|
||||
like any other edit, the results are seen by everyone and satellite imagery
|
||||
is often out of date, so the road could simply be newly built.
|
||||
|
||||
You can delete a road by clicking on it to select it, then clicking the
|
||||
trash can icon or pressing the 'Delete' key.
|
||||
|
||||
### Creating
|
||||
|
||||
Found somewhere there should be a road but there isn't? Click the 'Line'
|
||||
icon in the top-left of the editor or press the key '2' to start drawing
|
||||
a line.
|
||||
|
||||
Click on the start of the road on the map to start drawing. If the road
|
||||
connects to another road, first, click on the place where they connect.
|
||||
|
||||
Then click on points along the road so that it follows the right path, according
|
||||
to satellite imagery or GPS. When you're done drawing the road, double-click
|
||||
or press 'Return' or 'Enter' on your keyboard.
|
||||
@@ -0,0 +1,18 @@
|
||||
# GPS
|
||||
|
||||
GPS data is the most trusted source of data for OpenStreetMap. This editor
|
||||
supports local traces - `.gpx` files on your local computer. You can collect
|
||||
this kind of GPS trace with a number of smartphone applications as well as
|
||||
personal GPS hardware.
|
||||
|
||||
For information on how to perform a GPS survey, read
|
||||
[Surveying with a GPS](http://learnosm.org/en/beginner/using-gps/).
|
||||
|
||||
To use a GPX track for mapping, drag and drop the GPX file onto the map map
|
||||
editor. If it's recognized, it will be added to the map as a bright green
|
||||
line. Click on the 'Background Settings' menu on the left side to enable,
|
||||
disable, or zoom to this new GPX-powered layer.
|
||||
|
||||
The GPX track isn't directly uploaded to OpenStreetMap - the best way to
|
||||
use it is to draw on the map, using it as a guide for the new features that
|
||||
you add.
|
||||
@@ -0,0 +1,17 @@
|
||||
# Imagery
|
||||
|
||||
Aerial imagery is an important resource for mapping. A combination of
|
||||
airplane flyovers, satellite views, and freely-compiled sources are available
|
||||
in the editor under the 'Background Settings' menu on the left.
|
||||
|
||||
By default a [Bing Maps](http://www.bing.com/maps/) satellite layer is
|
||||
presented in the editor, but as you pan and zoom the map to new geographical
|
||||
areas, new sources will become available. Some countries, like the United
|
||||
States, France, and Denmark have very high-resolution, high-quality imagery
|
||||
available for smaller geographical coverages.
|
||||
|
||||
Imagery is sometimes offset from the map data because of a mistake on the
|
||||
imagery provider's side - so if you see many roads shifted from the background,
|
||||
don't immediately go to move them all. You can set an offset for imagery
|
||||
by clicking 'Fix alignment' at the bottom of the bottom of the Background
|
||||
Settings UI.
|
||||
@@ -0,0 +1,12 @@
|
||||
# Addresses
|
||||
|
||||
Addresses are some of the most useful information for the map.
|
||||
|
||||
Although addresses are often represented as parts of streets, in OpenStreetMap
|
||||
they're recorded as attributes of buildings and places along streets.
|
||||
|
||||
You can add address information to places mapped as building outlines as well
|
||||
as well as those mapped as single points. The optimal source of address
|
||||
data is from an on-the-ground survey or personal knowledge - as with any
|
||||
other feature, copying from commercial sources like Google Maps is strictly
|
||||
forbidden.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Using the Inspector
|
||||
|
||||
The inspector is the user interface element on the right-hand side of the
|
||||
page that appears when an element is selected and allows to edit its details.
|
||||
|
||||
### Selecting a Preset
|
||||
|
||||
The inspector has two modes: the first allows you to pick a preset, or
|
||||
predetermined selection of forms and tags.
|
||||
|
||||
Click the 'i' in the bottom-right-hand corner of a preset option to learn
|
||||
more about it. Click a preset to choose it.
|
||||
|
||||
### Using Forms and Editing Tags
|
||||
|
||||
The second allows you to edit the
|
||||
attributes of a map element using those forms and tags.
|
||||
|
||||
Below the forms you see, you can click icons to add more easy-to-use forms,
|
||||
like [Wikipedia](http://www.wikipedia.org/) information, wheelchair
|
||||
access, and more.
|
||||
|
||||
At the bottom of the inspector, click 'Additional tags' to add arbitrary
|
||||
other tags to the element. [Taginfo](http://taginfo.openstreetmap.org/) is a
|
||||
great resource for learn more about popular tag combinations.
|
||||
|
||||
Changes you make in the inspector are automatically applied to the map.
|
||||
You can undo them at any time by clicking the Undo button.
|
||||
|
||||
### Closing the Inspector
|
||||
|
||||
You can close the inspector by either clicking the close button in the top-right,
|
||||
pressing the 'Escape' key, or clicking on the map.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Buildings
|
||||
|
||||
OpenStreetMap is the world's largest database of buildings. You can create
|
||||
and improve this database.
|
||||
|
||||
### Selecting
|
||||
|
||||
You can select a building by clicking on its border. This will highlight the
|
||||
building and open a small tools menu and a sidebar showing more information
|
||||
about the building.
|
||||
|
||||
### Modifying
|
||||
|
||||
Sometimes buildings are incorrectly placed or have incorrect tags.
|
||||
|
||||
To move an entire building, select it, then click the 'Move' tool. Move your
|
||||
mouse to shift the building, and click when it's correctly placed.
|
||||
|
||||
To fix the specific shape of a building, click and drag the points that form
|
||||
its border into better places.
|
||||
|
||||
### Creating
|
||||
|
||||
One of the main questions around adding buildings to the map is that
|
||||
OpenStreetMap records buildings both as shapes and points. The rule of thumb
|
||||
is to _map a building as a shape whenever possible_, and map companies, homes,
|
||||
amenities, and other things that operate out of buildings as points placed
|
||||
within the building shape.
|
||||
|
||||
Start drawing a building as a shape by clicking the 'Area' button in the top
|
||||
left of the interface, and end it either by pressing 'Return' on your keyboard
|
||||
or clicking on the first point drawn to close the shape.
|
||||
|
||||
### Deleting
|
||||
|
||||
If a building is entirely incorrect - you can see that it doesn't exist in satellite
|
||||
imagery and ideally have confirmed locally that it's not present - you can delete
|
||||
it, which removes it from the map. Be cautious when deleting features -
|
||||
like any other edit, the results are seen by everyone and satellite imagery
|
||||
is often out of date, so the road could simply be newly built.
|
||||
|
||||
You can delete a building by clicking on it to select it, then clicking the
|
||||
trash can icon or pressing the 'Delete' key.
|
||||
@@ -372,6 +372,7 @@
|
||||
"key": "website",
|
||||
"type": "url",
|
||||
"icon": "website",
|
||||
"placeholder": "http://example.com/",
|
||||
"universal": true,
|
||||
"label": "Website"
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"key": "website",
|
||||
"type": "url",
|
||||
"icon": "website",
|
||||
"placeholder": "http://example.com/",
|
||||
"universal": true,
|
||||
"label": "Website"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,9 +59,12 @@
|
||||
"icon": {
|
||||
"type": "string"
|
||||
},
|
||||
"placeholder": {
|
||||
"type": "string"
|
||||
},
|
||||
"strings": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
@@ -9,7 +9,7 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="460"
|
||||
width="500"
|
||||
height="320"
|
||||
id="svg12393"
|
||||
version="1.1"
|
||||
@@ -39,8 +39,8 @@
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="237.92081"
|
||||
inkscape:cy="230.70164"
|
||||
inkscape:cx="319.99979"
|
||||
inkscape:cy="247.06899"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer12"
|
||||
showgrid="false"
|
||||
@@ -53,10 +53,11 @@
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
showguides="false"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-nodes="false">
|
||||
inkscape:snap-nodes="true"
|
||||
inkscape:snap-global="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid12420"
|
||||
@@ -192,6 +193,18 @@
|
||||
orientation="1,0"
|
||||
position="460,320"
|
||||
id="guide4067" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="401,270"
|
||||
id="guide6083" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="460,310"
|
||||
id="guide6106" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="480,345"
|
||||
id="guide3361" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata12398">
|
||||
@@ -201,7 +214,7 @@
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
@@ -214,8 +227,8 @@
|
||||
<rect
|
||||
style="color:#000000;fill:#323232;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect4478"
|
||||
width="440"
|
||||
height="200"
|
||||
width="500"
|
||||
height="310"
|
||||
x="25"
|
||||
y="62.362183" />
|
||||
</g>
|
||||
@@ -351,14 +364,9 @@
|
||||
id="path3769"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
<path
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 255,3.9999969 -1,1 0,1 1,1 1,0 1,-1 0,-1 -1,-1 -1,0 z m 0,4 -1,1 0,5.0000001 1,1 1,0 1,-1 0,-5.0000001 -1,-1 -1,0 z"
|
||||
id="path10936"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 113,2.01282 -5,4.5 5,4.5 0,-3 3,0 L 117,9 117,12.01282 116,13 l -5,0.0128 -1,1.00002 0,1 1,0.99998 5,0 2,-0.99998 1,-1 1,-2.00002 0,-3 -1,-1.99998 -1,-1 -2,-1.00002 -3,0 z"
|
||||
d="m 114,2.01282 -5,4.5 5,4.5 0,-3 3,0 L 118,9 118,12.01282 117,13 l -5,0.0128 -1,1.00002 0,1 1,0.99998 5,0 2,-0.99998 1,-1 1,-2.00002 0,-3 -1,-1.99998 -1,-1 -2,-1.00002 -3,0 z"
|
||||
id="path2997"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccccccccccccccc"
|
||||
@@ -671,7 +679,7 @@
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 113,42.01282 -5,4.5 5,4.5 0,-3 3,0 1,0.98718 0,3.01282 -1,0.98718 -5,0.0128 -1,1.00002 0,1 1,0.99998 5,0 2,-0.99998 1,-1 1,-2.00002 0,-3 -1,-1.99998 -1,-1 -2,-1.00002 -3,0 z"
|
||||
d="m 114,42.01282 -5,4.5 5,4.5 0,-3 3,0 1,0.98718 0,3.01282 -1,0.98718 -5,0.0128 -1,1.00002 0,1 1,0.99998 5,0 2,-0.99998 1,-1 1,-2.00002 0,-3 -1,-1.99998 -1,-1 -2,-1.00002 -3,0 z"
|
||||
id="path16239"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccccccccccccccc"
|
||||
@@ -835,7 +843,7 @@
|
||||
sodipodi:nodetypes="cccccccccccccccccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path33325"
|
||||
d="m 113,22.01282 -5,4.5 5,4.5 0,-3 3,0 1,0.98718 0,3.01282 -1,0.98718 -5,0.0128 -1,1.00002 0,1 1,0.99998 5,0 2,-0.99998 1,-1 1,-2.00002 0,-3 -1,-1.99998 -1,-1 -2,-1.00002 -3,0 z"
|
||||
d="m 114,22.01282 -5,4.5 5,4.5 0,-3 3,0 1,0.98718 0,3.01282 -1,0.98718 -5,0.0128 -1,1.00002 0,1 1,0.99998 5,0 2,-0.99998 1,-1 1,-2.00002 0,-3 -1,-1.99998 -1,-1 -2,-1.00002 -3,0 z"
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
@@ -1190,9 +1198,9 @@
|
||||
<rect
|
||||
style="color:#000000;fill:none;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect10175"
|
||||
width="460"
|
||||
width="500"
|
||||
height="320"
|
||||
x="-485"
|
||||
x="-525"
|
||||
y="-3.0624999e-06"
|
||||
transform="scale(-1,1)" />
|
||||
<path
|
||||
@@ -2059,5 +2067,44 @@
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
</g>
|
||||
<g
|
||||
id="g3815"
|
||||
transform="translate(0,50)"
|
||||
style="fill:#1a1a1a;fill-opacity:1">
|
||||
<path
|
||||
style="color:#000000;fill:#1a1a1a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="M 464 2 L 463 3 L 463 16 L 464 17 L 475 17 L 476 16 L 476 6 L 472 6 L 472 12 L 469.5 10.5 L 467 12 L 467 6 L 465 6 L 465 5 L 465 4 L 476 4 L 476 3 L 476 2 L 464 2 z "
|
||||
transform="translate(25,-50.000003)"
|
||||
id="path3648" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(0,70)"
|
||||
id="g3822">
|
||||
<path
|
||||
id="path3824"
|
||||
transform="translate(25,-50.000003)"
|
||||
d="m 464,2 -1,1 0,13 1,1 11,0 1,-1 0,-10 -4,0 0,6 -2.5,-1.5 -2.5,1.5 0,-6 -2,0 0,-1 0,-1 11,0 0,-1 0,-1 -12,0 z"
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
id="g3837"
|
||||
transform="translate(-1,0)" />
|
||||
<g
|
||||
id="g3842"
|
||||
transform="translate(0,20)"
|
||||
style="fill:#ffffff" />
|
||||
<path
|
||||
style="color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m 251,4.9999969 1.125,-1 6.75,0 1.125,1 0,10.0000001 -1.125,1 -3.375,-2.886751 -3.375,2.886751 -1.125,-1 z"
|
||||
id="path3854"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3874"
|
||||
d="m 251,24.999997 1.125,-1 6.75,0 1.125,1 0,10 -1.125,1 -3.375,-2.886751 -3.375,2.886751 -1.125,-1 z"
|
||||
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 22 KiB |
@@ -23,6 +23,7 @@
|
||||
<script src='js/lib/d3.geo.tile.js'></script>
|
||||
<script src='js/lib/d3.size.js'></script>
|
||||
<script src='js/lib/d3.trigger.js'></script>
|
||||
<script src='js/lib/d3.jsonp.js'></script>
|
||||
<script src='js/lib/d3.keybinding.js'></script>
|
||||
<script src='js/lib/d3.curtain.js'></script>
|
||||
<script src='js/lib/d3.one.js'></script>
|
||||
@@ -73,6 +74,7 @@
|
||||
<script src='js/id/ui/modes.js'></script>
|
||||
<script src='js/id/ui/contributors.js'></script>
|
||||
<script src='js/id/ui/geocoder.js'></script>
|
||||
<script src='js/id/ui/help.js'></script>
|
||||
<script src='js/id/ui/geolocate.js'></script>
|
||||
<script src='js/id/ui/notice.js'></script>
|
||||
<script src='js/id/ui/flash.js'></script>
|
||||
@@ -81,7 +83,6 @@
|
||||
<script src='js/id/ui/spinner.js'></script>
|
||||
<script src='js/id/ui/restore.js'></script>
|
||||
<script src='js/id/ui/tag_reference.js'></script>
|
||||
<script src='js/id/ui/key_reference.js'></script>
|
||||
<script src='js/id/ui/preset.js'></script>
|
||||
<script src='js/id/ui/lasso.js'></script>
|
||||
<script src='js/id/ui/source_switch.js'></script>
|
||||
|
||||
@@ -6,34 +6,54 @@ iD.actions.Orthogonalize = function(wayId, projection) {
|
||||
var action = function(graph) {
|
||||
var way = graph.entity(wayId),
|
||||
nodes = graph.childNodes(way),
|
||||
points = nodes.map(function(n) { return projection(n.loc); }),
|
||||
best, i, j;
|
||||
corner = {i: 0, dotp: 1},
|
||||
points, i, j, score, motions;
|
||||
|
||||
var score = squareness();
|
||||
for (i = 0; i < 1000; i++) {
|
||||
var motions = points.map(stepMap);
|
||||
for (j = 0; j < motions.length; j++) {
|
||||
points[j] = addPoints(points[j],motions[j]);
|
||||
}
|
||||
var newScore = squareness();
|
||||
if (newScore < score) {
|
||||
best = _.clone(points);
|
||||
score = newScore;
|
||||
}
|
||||
if (score < 1.0e-8) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
points = best;
|
||||
if (nodes.length === 4) {
|
||||
points = _.uniq(nodes).map(function(n) { return projection(n.loc); });
|
||||
|
||||
for (i = 0; i < points.length - 1; i++) {
|
||||
graph = graph.replace(graph.entity(nodes[i].id)
|
||||
.move(projection.invert(points[i])));
|
||||
for (i = 0; i < 1000; i++) {
|
||||
motions = points.map(calcMotion);
|
||||
points[corner.i] = addPoints(points[corner.i],motions[corner.i]);
|
||||
score = corner.dotp;
|
||||
if (score < 1.0e-8) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
graph = graph.replace(graph.entity(nodes[corner.i].id)
|
||||
.move(projection.invert(points[corner.i])));
|
||||
} else {
|
||||
var best;
|
||||
points = nodes.map(function(n) { return projection(n.loc); });
|
||||
score = squareness();
|
||||
|
||||
for (i = 0; i < 1000; i++) {
|
||||
motions = points.map(calcMotion);
|
||||
for (j = 0; j < motions.length; j++) {
|
||||
points[j] = addPoints(points[j],motions[j]);
|
||||
}
|
||||
var newScore = squareness();
|
||||
if (newScore < score) {
|
||||
best = _.clone(points);
|
||||
score = newScore;
|
||||
}
|
||||
if (score < 1.0e-8) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
points = best;
|
||||
|
||||
for (i = 0; i < points.length - 1; i++) {
|
||||
graph = graph.replace(graph.entity(nodes[i].id)
|
||||
.move(projection.invert(points[i])));
|
||||
}
|
||||
}
|
||||
|
||||
return graph;
|
||||
|
||||
function stepMap(b, i, array) {
|
||||
function calcMotion(b, i, array) {
|
||||
var a = array[(i - 1 + array.length) % array.length],
|
||||
c = array[(i + 1) % array.length],
|
||||
p = subtractPoints(a, b),
|
||||
@@ -44,9 +64,15 @@ iD.actions.Orthogonalize = function(wayId, projection) {
|
||||
q = normalizePoint(q, 1.0);
|
||||
|
||||
var dotp = p[0] * q[0] + p[1] * q[1];
|
||||
|
||||
// nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
|
||||
if (dotp < -0.707106781186547) {
|
||||
dotp += 1.0;
|
||||
if (array.length > 3) {
|
||||
if (dotp < -0.707106781186547) {
|
||||
dotp += 1.0;
|
||||
}
|
||||
} else if (Math.abs(dotp) < corner.dotp) {
|
||||
corner.i = i;
|
||||
corner.dotp = Math.abs(dotp);
|
||||
}
|
||||
|
||||
return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
|
||||
@@ -86,7 +112,7 @@ iD.actions.Orthogonalize = function(wayId, projection) {
|
||||
return [a[0] + b[0], a[1] + b[1]];
|
||||
}
|
||||
|
||||
function normalizePoint(point, thickness) {
|
||||
function normalizePoint(point, scale) {
|
||||
var vector = [0, 0];
|
||||
var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
|
||||
if (length !== 0) {
|
||||
@@ -94,8 +120,8 @@ iD.actions.Orthogonalize = function(wayId, projection) {
|
||||
vector[1] = point[1] / length;
|
||||
}
|
||||
|
||||
vector[0] *= thickness;
|
||||
vector[1] *= thickness;
|
||||
vector[0] *= scale;
|
||||
vector[1] *= scale;
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
@@ -102,7 +102,13 @@ window.iD = function () {
|
||||
context.zoomOut = map.zoomOut;
|
||||
|
||||
/* Background */
|
||||
var backgroundSources = iD.data.imagery.map(iD.BackgroundSource.template);
|
||||
var backgroundSources = iD.data.imagery.map(function(source) {
|
||||
if (source.sourcetag === 'Bing') {
|
||||
return iD.BackgroundSource.Bing(source, context.background().dispatch);
|
||||
} else {
|
||||
return iD.BackgroundSource.template(source);
|
||||
}
|
||||
});
|
||||
backgroundSources.push(iD.BackgroundSource.Custom);
|
||||
|
||||
context.backgroundSources = function() {
|
||||
|
||||
@@ -4,6 +4,7 @@ iD.operations.Disconnect = function(selection, context) {
|
||||
|
||||
var operation = function() {
|
||||
context.perform(action, t('operations.disconnect.annotation'));
|
||||
context.enter(iD.modes.Browse(context));
|
||||
};
|
||||
|
||||
operation.available = function() {
|
||||
|
||||
@@ -10,7 +10,7 @@ iD.operations.Orthogonalize = function(selection, context) {
|
||||
operation.available = function() {
|
||||
return selection.length === 1 &&
|
||||
context.entity(entityId).type === 'way' &&
|
||||
_.uniq(context.entity(entityId).nodes).length > 3;
|
||||
_.uniq(context.entity(entityId).nodes).length > 2;
|
||||
};
|
||||
|
||||
operation.enabled = function() {
|
||||
|
||||
@@ -168,14 +168,17 @@ iD.Background = function() {
|
||||
}
|
||||
}
|
||||
|
||||
background.dispatch = d3.dispatch('change');
|
||||
|
||||
background.source = function(_) {
|
||||
if (!arguments.length) return source;
|
||||
source = _;
|
||||
cache = {};
|
||||
tile.scaleExtent((source.data && source.data.scaleExtent) || [1, 20]);
|
||||
setHash(source);
|
||||
background.dispatch.change();
|
||||
return background;
|
||||
};
|
||||
|
||||
return background;
|
||||
return d3.rebind(background, background.dispatch, 'on');
|
||||
};
|
||||
|
||||
@@ -29,12 +29,55 @@ iD.BackgroundSource.template = function(data) {
|
||||
}
|
||||
|
||||
generator.data = data;
|
||||
generator.copyrightNotices = function() {};
|
||||
|
||||
return generator;
|
||||
};
|
||||
|
||||
iD.BackgroundSource.Bing = function(data, dispatch) {
|
||||
// http://msdn.microsoft.com/en-us/library/ff701716.aspx
|
||||
// http://msdn.microsoft.com/en-us/library/ff701701.aspx
|
||||
|
||||
var bing = iD.BackgroundSource.template(data),
|
||||
key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
|
||||
url = 'http://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
|
||||
key + '&jsonp={callback}',
|
||||
providers = [];
|
||||
|
||||
d3.jsonp(url, function(json) {
|
||||
providers = json.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
|
||||
return {
|
||||
attribution: provider.attribution,
|
||||
areas: provider.coverageAreas.map(function(area) {
|
||||
return {
|
||||
zoom: [area.zoomMin, area.zoomMax],
|
||||
extent: iD.geo.Extent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
|
||||
};
|
||||
})
|
||||
};
|
||||
});
|
||||
dispatch.change();
|
||||
});
|
||||
|
||||
bing.copyrightNotices = function(zoom, extent) {
|
||||
zoom = Math.min(zoom, 21);
|
||||
return providers.filter(function(provider) {
|
||||
return _.any(provider.areas, function(area) {
|
||||
return extent.intersects(area.extent) &&
|
||||
area.zoom[0] <= zoom &&
|
||||
area.zoom[1] >= zoom;
|
||||
});
|
||||
}).map(function(provider) {
|
||||
return provider.attribution;
|
||||
}).join(', ');
|
||||
};
|
||||
|
||||
return bing;
|
||||
};
|
||||
|
||||
iD.BackgroundSource.Custom = function() {
|
||||
var template = window.prompt('Enter a tile template. Valid tokens are {z}, {x}, {y} for Z/X/Y scheme and {u} for quadtile scheme.');
|
||||
var template = window.prompt('Enter a tile template. ' +
|
||||
'Valid tokens are {z}, {x}, {y} for Z/X/Y scheme and {u} for quadtile scheme.');
|
||||
if (!template) return null;
|
||||
return iD.BackgroundSource.template({
|
||||
template: template,
|
||||
|
||||
@@ -5,6 +5,17 @@ iD.svg.Surface = function() {
|
||||
});
|
||||
}
|
||||
|
||||
function autosize(image) {
|
||||
var img = document.createElement('img');
|
||||
img.src = image.attr('xlink:href');
|
||||
img.onload = function() {
|
||||
image.attr({
|
||||
width: img.width,
|
||||
height: img.height
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function sprites(stylesheetName, selectorRegexp) {
|
||||
var sprites = [];
|
||||
|
||||
@@ -90,12 +101,9 @@ iD.svg.Surface = function() {
|
||||
.attr('height', function(d) { return d; });
|
||||
|
||||
defs.append('image')
|
||||
.attr({
|
||||
id: 'sprite',
|
||||
width: 460,
|
||||
height: 320,
|
||||
'xlink:href': 'img/sprite.png'
|
||||
});
|
||||
.attr('id', 'sprite')
|
||||
.attr('xlink:href', 'img/sprite.png')
|
||||
.call(autosize);
|
||||
|
||||
defs.selectAll()
|
||||
.data(sprites("app.css", /^\.(icon-operation-[a-z0-9-]+)$/))
|
||||
@@ -104,20 +112,10 @@ iD.svg.Surface = function() {
|
||||
.attr('transform', function(d) { return "translate(" + d.x + "," + d.y + ")"; })
|
||||
.attr('xlink:href', '#sprite');
|
||||
|
||||
var image = defs.append('image')
|
||||
.attr({
|
||||
id: 'maki-sprite',
|
||||
'xlink:href': 'img/feature-icons.png'
|
||||
});
|
||||
|
||||
var img = document.createElement('img');
|
||||
img.src = 'img/feature-icons.png';
|
||||
img.onload = function() {
|
||||
image.attr({
|
||||
width: img.width,
|
||||
height: img.height
|
||||
});
|
||||
};
|
||||
defs.append('image')
|
||||
.attr('id', 'maki-sprite')
|
||||
.attr('xlink:href', 'img/feature-icons.png')
|
||||
.call(autosize);
|
||||
|
||||
defs.selectAll()
|
||||
.data(sprites("feature-icons.css", /^\.(feature-[a-z0-9-]+-(12|18))$/))
|
||||
|
||||
@@ -69,13 +69,13 @@ iD.svg.Vertices = function(projection, context) {
|
||||
groups.select('circle.shadow')
|
||||
.each(center)
|
||||
.attr('r', function(entity) {
|
||||
return radiuses.shadow[icon(entity) ? 3 : zoom]
|
||||
return radiuses.shadow[icon(entity) ? 3 : zoom];
|
||||
});
|
||||
|
||||
groups.select('circle.stroke')
|
||||
.each(center)
|
||||
.attr('r', function(entity) {
|
||||
return radiuses.stroke[icon(entity) ? 3 : zoom]
|
||||
return radiuses.stroke[icon(entity) ? 3 : zoom];
|
||||
});
|
||||
|
||||
// Each vertex gets either a circle or a use, depending
|
||||
|
||||
@@ -52,6 +52,10 @@ iD.ui = function(context) {
|
||||
.attr('class', 'spinner')
|
||||
.call(iD.ui.Spinner(context));
|
||||
|
||||
container.append('div')
|
||||
.style('display', 'none')
|
||||
.attr('class', 'help-wrap fillL col5');
|
||||
|
||||
container.append('div')
|
||||
.attr('class', 'map-control zoombuttons')
|
||||
.call(iD.ui.Zoom(context));
|
||||
@@ -68,10 +72,19 @@ iD.ui = function(context) {
|
||||
.attr('class', 'map-control geolocate-control')
|
||||
.call(iD.ui.Geolocate(map));
|
||||
|
||||
container.append('div')
|
||||
.attr('class', 'map-control help-control')
|
||||
.call(iD.ui.Help(context));
|
||||
|
||||
container.append('div')
|
||||
.style('display', 'none')
|
||||
.attr('class', 'inspector-wrap fr content col4');
|
||||
|
||||
container.append('idv')
|
||||
.attr('class', 'attribution')
|
||||
.attr('tabindex', -1)
|
||||
.call(iD.ui.Attribution(context));
|
||||
|
||||
var about = container.append('div')
|
||||
.attr('class','col12 about-block fillD');
|
||||
|
||||
@@ -97,12 +110,6 @@ iD.ui = function(context) {
|
||||
.attr('href', 'https://help.openstreetmap.org/questions/ask/')
|
||||
.text(t('report_a_bug'));
|
||||
|
||||
linkList.append('li')
|
||||
.attr('class', 'attribution')
|
||||
.attr('tabindex', -1)
|
||||
.data([context.background().source()])
|
||||
.call(iD.ui.Attribution(context));
|
||||
|
||||
linkList.append('li')
|
||||
.attr('class', 'source-switch')
|
||||
.call(iD.ui.SourceSwitch(context));
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
iD.ui.Attribution = function(context) {
|
||||
return function attribution(selection) {
|
||||
var d = selection.data()[0];
|
||||
var selection;
|
||||
|
||||
function update() {
|
||||
var d = context.background().source();
|
||||
|
||||
var provided_by = selection
|
||||
.html('')
|
||||
@@ -9,18 +11,36 @@ iD.ui.Attribution = function(context) {
|
||||
|
||||
if (!d) return;
|
||||
|
||||
var desc = t('imagery.provided_by', {
|
||||
source: (d.data.sourcetag || d.data.name)
|
||||
});
|
||||
var source = d.data.sourcetag || d.data.name;
|
||||
if (d.data.logo) {
|
||||
source = '<img class="source-image" src="img/' + d.data.logo + '">';
|
||||
}
|
||||
|
||||
if (d.data.terms_url) {
|
||||
provided_by.append('a')
|
||||
.attr('href', (d.data.terms_url || ''))
|
||||
.attr('href', d.data.terms_url)
|
||||
.attr('target', '_blank')
|
||||
.classed('disabled', !d.data.terms_url)
|
||||
.text(desc);
|
||||
.html(source);
|
||||
} else {
|
||||
provided_by.text(desc);
|
||||
provided_by.text(source);
|
||||
}
|
||||
|
||||
var copyright = d.copyrightNotices(context.map().zoom(), context.map().extent());
|
||||
if (copyright) {
|
||||
provided_by.append('span')
|
||||
.text(copyright);
|
||||
}
|
||||
}
|
||||
|
||||
return function(select) {
|
||||
selection = select;
|
||||
|
||||
context.background()
|
||||
.on('change.attribution', update);
|
||||
|
||||
context.map()
|
||||
.on('move.attribution', _.throttle(update, 400));
|
||||
|
||||
update();
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
iD.ui.Background = function(context) {
|
||||
var event = d3.dispatch('cancel', 'save'),
|
||||
key = 'b',
|
||||
var key = 'b',
|
||||
opacities = [1, 0.5, 0],
|
||||
directions = [
|
||||
['left', [1, 0]],
|
||||
@@ -57,16 +56,11 @@ iD.ui.Background = function(context) {
|
||||
}
|
||||
}
|
||||
|
||||
function selectLayer(d) {
|
||||
function selectLayer() {
|
||||
content.selectAll('a.layer')
|
||||
.classed('selected', function(d) {
|
||||
return d.data.name === context.background().source().data.name;
|
||||
});
|
||||
|
||||
context.container()
|
||||
.select('.attribution')
|
||||
.data([d])
|
||||
.call(iD.ui.Attribution(context));
|
||||
}
|
||||
|
||||
function clickSetSource(d) {
|
||||
@@ -85,7 +79,7 @@ iD.ui.Background = function(context) {
|
||||
.imagery_used(d.data.sourcetag || d.data.name);
|
||||
}
|
||||
context.redraw();
|
||||
selectLayer(d);
|
||||
selectLayer();
|
||||
}
|
||||
|
||||
function clickGpx(d) {
|
||||
@@ -139,7 +133,7 @@ iD.ui.Background = function(context) {
|
||||
layerLinks.exit()
|
||||
.remove();
|
||||
|
||||
selectLayer(context.background().source());
|
||||
selectLayer();
|
||||
}
|
||||
|
||||
function clickNudge(d) {
|
||||
@@ -289,5 +283,5 @@ iD.ui.Background = function(context) {
|
||||
.call(keybinding);
|
||||
}
|
||||
|
||||
return d3.rebind(background, event, 'on');
|
||||
return background;
|
||||
};
|
||||
|
||||
@@ -36,10 +36,10 @@ iD.ui.Commit = function(context) {
|
||||
|
||||
// Comment Section
|
||||
var commentSection = body.append('div')
|
||||
.attr('class', 'modal-section preset-field');
|
||||
.attr('class', 'modal-section form-field');
|
||||
|
||||
commentSection.append('h4')
|
||||
.attr('for','input-commit-note')
|
||||
commentSection.append('label')
|
||||
.attr('class','form-label')
|
||||
.text(t('commit.message_label'));
|
||||
|
||||
var commentField = commentSection
|
||||
|
||||
@@ -82,6 +82,10 @@ iD.ui.Geocoder = function(context) {
|
||||
gcForm.call(iD.ui.Toggle(show));
|
||||
if (!show && !resultsList.classed('hide')) {
|
||||
resultsList.call(iD.ui.Toggle(show));
|
||||
// remove results so that they lose focus. if the user has
|
||||
// tabbed into the list, then they will have focus still,
|
||||
// even if they're hidden.
|
||||
resultsList.selectAll('span').remove();
|
||||
}
|
||||
if (show) inputNode.node().focus();
|
||||
else inputNode.node().blur();
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
iD.ui.Help = function(context) {
|
||||
|
||||
var key = 'h';
|
||||
|
||||
function help(selection) {
|
||||
|
||||
var shown = false, pane;
|
||||
|
||||
function setup() {
|
||||
pane = context.container()
|
||||
.select('.help-wrap')
|
||||
.html('');
|
||||
|
||||
var toc = pane.append('ul')
|
||||
.attr('class', 'toc');
|
||||
|
||||
function clickHelp(d) {
|
||||
doctitle.text(d.title);
|
||||
body.html(d.html);
|
||||
body.selectAll('a')
|
||||
.attr('target', '_blank');
|
||||
menuItems.classed('selected', function(m) {
|
||||
return m.title === d.title;
|
||||
});
|
||||
}
|
||||
|
||||
var menuItems = toc.selectAll('li')
|
||||
.data(iD.data.doc)
|
||||
.enter()
|
||||
.append('li')
|
||||
.append('a')
|
||||
.text(function(d) { return d.title; })
|
||||
.on('click', clickHelp);
|
||||
|
||||
var content = pane.append('div')
|
||||
.attr('class', 'left-content'),
|
||||
doctitle = content.append('h2')
|
||||
.text(t('help.title')),
|
||||
body = content.append('div')
|
||||
.attr('class', 'body');
|
||||
|
||||
clickHelp(iD.data.doc[0]);
|
||||
}
|
||||
|
||||
function hide() { setVisible(false); }
|
||||
function toggle() {
|
||||
if (d3.event) d3.event.preventDefault();
|
||||
tooltip.hide(button);
|
||||
setVisible(!button.classed('active'));
|
||||
}
|
||||
|
||||
function blockClick() {
|
||||
pane.on('mousedown.help-inside', function() {
|
||||
return d3.event.stopPropagation();
|
||||
});
|
||||
selection.on('mousedown.help-inside', function() {
|
||||
return d3.event.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
function setVisible(show) {
|
||||
if (show !== shown) {
|
||||
button.classed('active', show);
|
||||
shown = show;
|
||||
if (show) {
|
||||
pane.style('display', 'block')
|
||||
.style('left', '-500px')
|
||||
.transition()
|
||||
.duration(200)
|
||||
.style('left', '0px')
|
||||
.each('end', blockClick);
|
||||
} else {
|
||||
pane.style('left', '0px')
|
||||
.transition()
|
||||
.duration(200)
|
||||
.style('left', '-500px')
|
||||
.each('end', function() {
|
||||
d3.select(this).style('display', 'none');
|
||||
});
|
||||
pane.on('mousedown.help-inside', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var tooltip = bootstrap.tooltip()
|
||||
.placement('right')
|
||||
.html(true)
|
||||
.title(iD.ui.tooltipHtml(t('help.title'), key));
|
||||
|
||||
var button = selection.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.on('click', toggle)
|
||||
.call(tooltip);
|
||||
|
||||
button.append('span')
|
||||
.attr('class', 'icon help light');
|
||||
|
||||
context.surface().on('mousedown.help-outside', hide);
|
||||
context.container().on('mousedown.b.help-outside', hide);
|
||||
|
||||
setup();
|
||||
|
||||
var keybinding = d3.keybinding('help');
|
||||
keybinding.on(key, toggle);
|
||||
d3.select(document).call(keybinding);
|
||||
}
|
||||
|
||||
return help;
|
||||
};
|
||||
@@ -2,7 +2,8 @@ iD.ui.Inspector = function(context, entity) {
|
||||
var tagEditor;
|
||||
|
||||
function changeTags(tags) {
|
||||
if (!_.isEqual(entity.tags, tags)) {
|
||||
entity = context.entity(entity.id);
|
||||
if (entity && !_.isEqual(entity.tags, tags)) {
|
||||
context.perform(
|
||||
iD.actions.ChangeTags(entity.id, tags),
|
||||
t('operations.change_tags.annotation'));
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
iD.ui.keyReference = function(selection) {
|
||||
selection.each(function() {
|
||||
|
||||
var selection = d3.select(this),
|
||||
data = selection.datum(),
|
||||
header = selection.append('div')
|
||||
.attr('class','modal-section fillL')
|
||||
.append('h2'),
|
||||
body = selection.append('div')
|
||||
.attr('class', 'modal-section fillL2');
|
||||
|
||||
header.append('span').attr('class', 'icon big icon-pre-text big-' + data.geometry);
|
||||
header.append('span').text(data.title);
|
||||
body.append('h3').text('Common Values');
|
||||
|
||||
var table = body.append('table')
|
||||
.attr('class', 'tags'),
|
||||
thead = table.append('thead');
|
||||
|
||||
thead.append('th').text('Value');
|
||||
thead.append('th').text('Description');
|
||||
thead.append('th').text('Count');
|
||||
|
||||
var rows = table.selectAll('tr')
|
||||
.data(data.data)
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
var cols = rows.selectAll('td')
|
||||
.data(function(d) {
|
||||
return [d.value, d.description || "", d.count];
|
||||
})
|
||||
.enter()
|
||||
.append('td')
|
||||
.text(String);
|
||||
});
|
||||
};
|
||||
@@ -1,109 +1,212 @@
|
||||
iD.ui.preset = function(context, entity) {
|
||||
var event = d3.dispatch('change', 'setTags', 'close'),
|
||||
tags,
|
||||
keys,
|
||||
preset,
|
||||
iD.ui.preset = function(context, entity, preset) {
|
||||
var original = context.graph().base().entities[entity.id],
|
||||
event = d3.dispatch('change', 'close'),
|
||||
fields = [],
|
||||
tags = {},
|
||||
formwrap,
|
||||
formbuttonwrap;
|
||||
|
||||
function presets(selection) {
|
||||
selection.html('');
|
||||
function UIField(field, show) {
|
||||
field = _.clone(field);
|
||||
|
||||
keys = [];
|
||||
formwrap = selection.append('div');
|
||||
field.input = iD.ui.preset[field.type](field, context)
|
||||
.on('close', event.close)
|
||||
.on('change', event.change);
|
||||
|
||||
var geometry = entity.geometry(context.graph()),
|
||||
fields = preset.fields.filter(function(f) {
|
||||
return f.matchGeometry(geometry);
|
||||
if (field.type === 'address') {
|
||||
field.input.entity(entity);
|
||||
}
|
||||
|
||||
field.keys = field.keys || [field.key];
|
||||
|
||||
field.show = show;
|
||||
|
||||
field.shown = function() {
|
||||
return field.id === 'name' || field.show || _.any(field.keys, function(key) { return !!tags[key]; });
|
||||
};
|
||||
|
||||
field.modified = function() {
|
||||
return _.any(field.keys, function(key) {
|
||||
return original ? tags[key] !== original.tags[key] : tags[key];
|
||||
});
|
||||
};
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
fields.push(UIField(context.presets().field('name')));
|
||||
|
||||
var geometry = entity.geometry(context.graph());
|
||||
preset.fields.forEach(function(field) {
|
||||
if (field.matchGeometry(geometry)) {
|
||||
fields.push(UIField(field, true));
|
||||
}
|
||||
});
|
||||
|
||||
context.presets().universal().forEach(function(field) {
|
||||
if (fields.indexOf(field) < 0) {
|
||||
fields.push(UIField(field));
|
||||
}
|
||||
});
|
||||
|
||||
function fieldKey(field) {
|
||||
return field.id;
|
||||
}
|
||||
|
||||
function shown() {
|
||||
return fields.filter(function(field) { return field.shown(); });
|
||||
}
|
||||
|
||||
function notShown() {
|
||||
return fields.filter(function(field) { return !field.shown(); });
|
||||
}
|
||||
|
||||
function show(field) {
|
||||
field.show = true;
|
||||
render();
|
||||
field.input.focus();
|
||||
}
|
||||
|
||||
function revert(field) {
|
||||
d3.event.stopPropagation();
|
||||
d3.event.preventDefault();
|
||||
var t = {};
|
||||
field.keys.forEach(function(key) {
|
||||
t[key] = original ? original.tags[key] : undefined;
|
||||
});
|
||||
event.change(t);
|
||||
}
|
||||
|
||||
function toggleReference(field) {
|
||||
d3.event.stopPropagation();
|
||||
d3.event.preventDefault();
|
||||
_.forEach(fields, function(other) {
|
||||
if (other.id === field.id) {
|
||||
other.showingReference = !other.showingReference;
|
||||
} else {
|
||||
other.showingReference = false;
|
||||
}
|
||||
});
|
||||
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
var selection = formwrap.selectAll('.form-field')
|
||||
.data(shown(), fieldKey);
|
||||
|
||||
var enter = selection.enter()
|
||||
.insert('div', '.more-buttons')
|
||||
.style('opacity', 0)
|
||||
.attr('class', function(field) {
|
||||
return 'form-field form-field-' + field.id + ' fillL col12';
|
||||
});
|
||||
|
||||
fields.unshift(context.presets().field('name'));
|
||||
enter.transition()
|
||||
.style('max-height', '0px')
|
||||
.style('padding-top', '0px')
|
||||
.style('opacity', '0')
|
||||
.transition()
|
||||
.duration(200)
|
||||
.style('padding-top', '20px')
|
||||
.style('max-height', '200px')
|
||||
.style('opacity', '1');
|
||||
|
||||
draw(formwrap, fields);
|
||||
var label = enter.append('label')
|
||||
.attr('class', 'form-label')
|
||||
.attr('for', function(field) { return 'preset-input-' + field.id; })
|
||||
.text(function(field) { return field.label(); });
|
||||
|
||||
var wrap = selection.append('div')
|
||||
.attr('class', 'col12 more-buttons inspector-inner');
|
||||
label.append('button')
|
||||
.attr('class', 'tag-reference-button fr')
|
||||
.attr('tabindex', -1)
|
||||
.on('click', toggleReference)
|
||||
.append('span')
|
||||
.attr('class', 'icon inspect');
|
||||
|
||||
formbuttonwrap = wrap.append('div')
|
||||
.attr('class', 'col12 preset-input');
|
||||
label.append('button')
|
||||
.attr('class', 'fr modified-icon')
|
||||
.attr('tabindex', -1)
|
||||
.on('click', revert)
|
||||
.append('div')
|
||||
.attr('class','icon undo');
|
||||
|
||||
formbuttonwrap.selectAll('button')
|
||||
.data(context.presets().universal().filter(notInForm))
|
||||
.enter()
|
||||
enter.each(function(field) {
|
||||
d3.select(this).call(field.input);
|
||||
});
|
||||
|
||||
enter.append('div')
|
||||
.attr('class', 'tag-help');
|
||||
|
||||
selection
|
||||
.classed('modified', function(field) {
|
||||
return field.modified();
|
||||
});
|
||||
|
||||
selection.selectAll('.tag-help')
|
||||
.style('display', function(field) {
|
||||
return field.showingReference ? 'block' : 'block';
|
||||
})
|
||||
.each(function(field) {
|
||||
if (field.showingReference) {
|
||||
d3.select(this)
|
||||
.call(iD.ui.TagReference(entity, {key: field.key}))
|
||||
.style('max-height', '0px')
|
||||
.style('padding-top', '0px')
|
||||
.style('opacity', '0')
|
||||
.transition()
|
||||
.duration(200)
|
||||
.style('padding-top', '20px')
|
||||
.style('max-height', '200px')
|
||||
.style('opacity', '1');
|
||||
} else {
|
||||
d3.select(this)
|
||||
.call(iD.ui.TagReference(entity, {key: field.key}))
|
||||
.transition()
|
||||
.duration(200)
|
||||
.style('max-height', '0px')
|
||||
.style('padding-top', '0px')
|
||||
.style('opacity', '0');
|
||||
}
|
||||
});
|
||||
|
||||
selection.exit()
|
||||
.remove();
|
||||
|
||||
var addFields = formbuttonwrap.selectAll('.preset-add-field')
|
||||
.data(notShown(), fieldKey);
|
||||
|
||||
addFields.enter()
|
||||
.append('button')
|
||||
.attr('class', 'preset-add-field')
|
||||
.on('click', addForm)
|
||||
.on('click', show)
|
||||
.call(bootstrap.tooltip()
|
||||
.placement('top')
|
||||
.title(function(d) { return d.label(); }))
|
||||
.append('span')
|
||||
.attr('class', function(d) { return 'icon ' + d.icon; });
|
||||
|
||||
function notInForm(p) {
|
||||
return preset.fields.indexOf(p) < 0;
|
||||
}
|
||||
addFields.exit()
|
||||
.transition()
|
||||
.style('opacity', 0)
|
||||
.remove();
|
||||
|
||||
function addForm(d) {
|
||||
draw(formwrap, [d]);
|
||||
|
||||
d3.select(this)
|
||||
.style('opacity', 1)
|
||||
.transition()
|
||||
.style('opacity', 0)
|
||||
.remove();
|
||||
|
||||
if (!wrap.selectAll('button').node()) {
|
||||
wrap.remove();
|
||||
}
|
||||
}
|
||||
return selection;
|
||||
}
|
||||
|
||||
function draw(selection, fields) {
|
||||
var sections = selection.selectAll('div.preset-field')
|
||||
.data(fields, function(field) { return field.id; })
|
||||
.enter()
|
||||
.append('div')
|
||||
.style('opacity', 0)
|
||||
.attr('class', function(field) {
|
||||
return 'preset-field preset-field-' + field.id + ' fillL inspector-inner col12';
|
||||
});
|
||||
function presets(selection) {
|
||||
selection.html('');
|
||||
|
||||
sections.append('h4')
|
||||
.attr('for', function(d) { return 'input-' + d.key; })
|
||||
.text(function(d) { return d.label(); })
|
||||
.append('button')
|
||||
.attr('class', 'fr icon undo modified-icon')
|
||||
.on('click', function(d) {
|
||||
var original = context.graph().base().entities[entity.id];
|
||||
var t = {};
|
||||
(d.keys || [d.key]).forEach(function(key) {
|
||||
t[key] = original ? original.tags[key] : undefined;
|
||||
});
|
||||
event.change(t);
|
||||
});
|
||||
formwrap = selection;
|
||||
|
||||
sections.transition()
|
||||
.style('opacity', 1);
|
||||
formbuttonwrap = selection.append('div')
|
||||
.attr('class', 'col12 more-buttons inspector-inner');
|
||||
|
||||
sections.each(function(field) {
|
||||
var i = iD.ui.preset[field.type](field, context)
|
||||
.on('close', event.close)
|
||||
.on('change', event.change);
|
||||
|
||||
event.on('setTags.' + field.key || field.type, function (tags) {
|
||||
i.tags(_.clone(tags));
|
||||
});
|
||||
|
||||
if (field.type === 'address') i.entity(entity);
|
||||
|
||||
keys = keys.concat(field.key ? [field.key] : field.keys);
|
||||
|
||||
d3.select(this).call(i);
|
||||
});
|
||||
render();
|
||||
}
|
||||
|
||||
presets.rendered = function() {
|
||||
return keys;
|
||||
return _.flatten(shown().map(function(field) { return field.keys; }));
|
||||
};
|
||||
|
||||
presets.preset = function(_) {
|
||||
@@ -112,27 +215,17 @@ iD.ui.preset = function(context, entity) {
|
||||
return presets;
|
||||
};
|
||||
|
||||
presets.change = function(t) {
|
||||
tags = t;
|
||||
presets.change = function(_) {
|
||||
tags = _;
|
||||
|
||||
function haveKey(k) { return k && !!tags[k]; }
|
||||
|
||||
formbuttonwrap.selectAll('button').each(function(p) {
|
||||
if (haveKey(p.key) || _.any(p.keys, haveKey)) {
|
||||
draw(formwrap, [p]);
|
||||
d3.select(this).remove();
|
||||
fields.forEach(function(field) {
|
||||
if (field.shown()) {
|
||||
field.input.tags(_);
|
||||
}
|
||||
});
|
||||
|
||||
formwrap.selectAll('div.preset-field')
|
||||
.classed('modified', function(d) {
|
||||
var original = context.graph().base().entities[entity.id];
|
||||
return _.any(d.keys || [d.key], function(key) {
|
||||
return original ? tags[key] !== original.tags[key] : tags[key];
|
||||
});
|
||||
});
|
||||
render();
|
||||
|
||||
event.setTags(tags);
|
||||
return presets;
|
||||
};
|
||||
|
||||
|
||||
@@ -41,15 +41,19 @@ iD.ui.preset.address = function(field, context) {
|
||||
|
||||
function close() { return iD.behavior.accept().on('accept', event.close); }
|
||||
|
||||
housename = selection.append('input')
|
||||
var wrap = selection.append('div')
|
||||
.attr('class', 'preset-input-wrap');
|
||||
|
||||
housename = wrap.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('placeholder', field.t('placeholders.housename'))
|
||||
.attr('class', 'addr-housename')
|
||||
.attr('id', 'preset-input-' + field.id)
|
||||
.on('blur', change)
|
||||
.on('change', change)
|
||||
.call(close());
|
||||
|
||||
housenumber = selection.append('input')
|
||||
housenumber = wrap.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('placeholder', field.t('placeholders.number'))
|
||||
.attr('class', 'addr-number')
|
||||
@@ -57,25 +61,21 @@ iD.ui.preset.address = function(field, context) {
|
||||
.on('change', change)
|
||||
.call(close());
|
||||
|
||||
var streetwrap = selection.append('span')
|
||||
.attr('class', 'input-wrap-position');
|
||||
|
||||
street = streetwrap.append('input')
|
||||
street = wrap.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('placeholder', field.t('placeholders.street'))
|
||||
.attr('class', 'addr-street')
|
||||
.on('blur', change)
|
||||
.on('change', change);
|
||||
.on('change', change)
|
||||
.call(d3.combobox().data(getStreets()));
|
||||
|
||||
city = selection.append('input')
|
||||
city = wrap.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('placeholder', field.t('placeholders.city'))
|
||||
.attr('class', 'addr-city')
|
||||
.on('blur', change)
|
||||
.on('change', change)
|
||||
.call(close());
|
||||
|
||||
streetwrap.call(d3.combobox().data(getStreets()));
|
||||
}
|
||||
|
||||
function change() {
|
||||
@@ -101,5 +101,9 @@ iD.ui.preset.address = function(field, context) {
|
||||
return address;
|
||||
};
|
||||
|
||||
address.focus = function() {
|
||||
housename.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(address, event, 'on');
|
||||
};
|
||||
|
||||
@@ -11,11 +11,13 @@ iD.ui.preset.check = function(field) {
|
||||
|
||||
selection.classed('checkselect', 'true');
|
||||
|
||||
label = selection.append('label');
|
||||
label = selection.append('label')
|
||||
.attr('class', 'preset-input-wrap');
|
||||
|
||||
box = label.append('input')
|
||||
.property('indeterminate', true)
|
||||
.attr('type', 'checkbox');
|
||||
.attr('type', 'checkbox')
|
||||
.attr('id', 'preset-input-' + field.id);
|
||||
|
||||
text = label.append('span')
|
||||
.text('unknown')
|
||||
@@ -38,5 +40,9 @@ iD.ui.preset.check = function(field) {
|
||||
label.classed('set', !!value);
|
||||
};
|
||||
|
||||
check.focus = function() {
|
||||
box.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(check, event, 'on');
|
||||
};
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
iD.ui.preset.combo = function(field) {
|
||||
|
||||
var event = d3.dispatch('change', 'close'),
|
||||
wrap,
|
||||
input;
|
||||
|
||||
function combo(selection) {
|
||||
|
||||
wrap = this.append('span').attr('class', 'input-wrap-position');
|
||||
|
||||
input = wrap.append('input')
|
||||
.attr('type', 'text')
|
||||
.on('change', change)
|
||||
.on('blur', change);
|
||||
|
||||
var combobox = d3.combobox();
|
||||
wrap.call(combobox);
|
||||
|
||||
input = selection.append('input')
|
||||
.attr('type', 'text')
|
||||
.attr('id', 'preset-input-' + field.id)
|
||||
.on('change', change)
|
||||
.on('blur', change)
|
||||
.call(combobox);
|
||||
|
||||
if (field.options) {
|
||||
options(field.options);
|
||||
@@ -51,5 +48,9 @@ iD.ui.preset.combo = function(field) {
|
||||
input.property('value', tags[field.key] || '');
|
||||
};
|
||||
|
||||
combo.focus = function() {
|
||||
input.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(combo, event, 'on');
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@ iD.ui.preset.defaultcheck = function(field) {
|
||||
|
||||
input = selection.append('input')
|
||||
.attr('type', 'checkbox')
|
||||
.attr('id', 'input-' + field.key)
|
||||
.attr('id', 'preset-input-' + field.id)
|
||||
.on('change', function() {
|
||||
var t = {};
|
||||
t[field.key] = input.property('checked') ? field.value || 'yes' : undefined;
|
||||
@@ -19,5 +19,9 @@ iD.ui.preset.defaultcheck = function(field) {
|
||||
input.property('checked', !!tags[field.key] && tags[field.key] !== 'no');
|
||||
};
|
||||
|
||||
check.focus = function() {
|
||||
input.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(check, event, 'on');
|
||||
};
|
||||
|
||||
@@ -10,6 +10,7 @@ iD.ui.preset.url = function(field) {
|
||||
function i(selection) {
|
||||
input = selection.append('input')
|
||||
.attr('type', field.type)
|
||||
.attr('id', 'preset-input-' + field.id)
|
||||
.attr('placeholder', field.placeholder || '')
|
||||
.on('blur', change)
|
||||
.on('change', change)
|
||||
@@ -51,5 +52,9 @@ iD.ui.preset.url = function(field) {
|
||||
input.property('value', tags[field.key] || '');
|
||||
};
|
||||
|
||||
i.focus = function() {
|
||||
input.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(i, event, 'on');
|
||||
};
|
||||
|
||||
@@ -6,18 +6,18 @@ iD.ui.preset.radio = function(field) {
|
||||
function radio(selection) {
|
||||
selection.classed('preset-radio', true);
|
||||
|
||||
var buttonwrap = selection.append('div').attr('class','radio-wrap');
|
||||
var buttonwrap = selection.append('div')
|
||||
.attr('class', 'preset-input-wrap radio-wrap');
|
||||
|
||||
buttons = buttonwrap.selectAll('button')
|
||||
.data(field.keys || field.options)
|
||||
.enter()
|
||||
.append('button')
|
||||
.text(function(d) { return field.t('options.' + d, { 'default': d }); })
|
||||
.on('click', function() {
|
||||
buttons.classed('active', false);
|
||||
d3.select(this).classed('active', true);
|
||||
change();
|
||||
});
|
||||
.text(function(d) { return field.t('options.' + d, { 'default': d }); })
|
||||
.on('click', function(d) {
|
||||
buttons.classed('active', function(e) { return d === e; });
|
||||
change();
|
||||
});
|
||||
|
||||
buttonwrap.append('button')
|
||||
.on('click', function() {
|
||||
@@ -52,5 +52,9 @@ iD.ui.preset.radio = function(field) {
|
||||
});
|
||||
};
|
||||
|
||||
radio.focus = function() {
|
||||
buttons.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(radio, event, 'on');
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ iD.ui.preset.textarea = function(field) {
|
||||
|
||||
function i(selection) {
|
||||
input = selection.append('textarea')
|
||||
.attr('id', 'preset-input-' + field.id)
|
||||
.attr('placeholder', field.placeholder || '')
|
||||
.attr('maxlength', 255)
|
||||
.on('blur', change)
|
||||
@@ -22,5 +23,9 @@ iD.ui.preset.textarea = function(field) {
|
||||
input.text(tags[field.key] || '');
|
||||
};
|
||||
|
||||
i.focus = function() {
|
||||
input.node().focus();
|
||||
};
|
||||
|
||||
return d3.rebind(i, event, 'on');
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
iD.ui.PresetGrid = function(context, entity) {
|
||||
var event = d3.dispatch('choose', 'close'),
|
||||
default_limit = 9,
|
||||
currently_drawn = 9,
|
||||
presets,
|
||||
taginfo = iD.taginfo();
|
||||
defaultLimit = 9,
|
||||
currentlyDrawn = 9,
|
||||
presets;
|
||||
|
||||
function presetgrid(selection, preset) {
|
||||
|
||||
@@ -15,7 +14,7 @@ iD.ui.PresetGrid = function(context, entity) {
|
||||
.attr('class', 'header fillL cf');
|
||||
|
||||
var message = messagewrap.append('h3')
|
||||
.attr('class', 'inspector-inner fl')
|
||||
.attr('class', 'inspector-inner')
|
||||
.text(t('inspector.choose'));
|
||||
|
||||
if (preset) {
|
||||
@@ -39,14 +38,14 @@ iD.ui.PresetGrid = function(context, entity) {
|
||||
.attr('class', 'preset-grid fillL cf')
|
||||
.data([context.presets().defaults(entity, 36).collection]);
|
||||
|
||||
var show_more = gridwrap.append('button')
|
||||
var showMore = gridwrap.append('button')
|
||||
.attr('class', 'fillL show-more')
|
||||
.text(t('inspector.show_more'))
|
||||
.on('click', function() {
|
||||
grid.call(drawGrid, (currently_drawn += default_limit));
|
||||
grid.call(drawGrid, (currentlyDrawn += defaultLimit));
|
||||
});
|
||||
|
||||
grid.call(drawGrid, default_limit);
|
||||
grid.call(drawGrid, defaultLimit);
|
||||
|
||||
var searchwrap = selection.append('div')
|
||||
.attr('class', 'preset-grid-search-wrap inspector-inner');
|
||||
@@ -76,7 +75,7 @@ iD.ui.PresetGrid = function(context, entity) {
|
||||
if (d3.event.keyCode === 13 && value.length) {
|
||||
choose(grid.selectAll('.grid-entry:first-child').datum());
|
||||
} else {
|
||||
currently_drawn = default_limit;
|
||||
currentlyDrawn = defaultLimit;
|
||||
grid.classed('filtered', value.length);
|
||||
if (value.length) {
|
||||
var results = presets.search(value);
|
||||
@@ -85,10 +84,10 @@ iD.ui.PresetGrid = function(context, entity) {
|
||||
search: value
|
||||
}));
|
||||
grid.data([results.collection])
|
||||
.call(drawGrid, default_limit);
|
||||
.call(drawGrid, defaultLimit);
|
||||
} else {
|
||||
grid.data([context.presets().defaults(entity, 36).collection])
|
||||
.call(drawGrid, default_limit);
|
||||
.call(drawGrid, defaultLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,7 +114,7 @@ iD.ui.PresetGrid = function(context, entity) {
|
||||
.attr('class', 'arrow');
|
||||
|
||||
subgrid.append('div')
|
||||
.attr('class', 'preset-grid fillL cf fl')
|
||||
.attr('class', 'preset-grid fillL3 cf fl')
|
||||
.data([d.members.collection])
|
||||
.call(drawGrid, 1000);
|
||||
|
||||
@@ -164,10 +163,7 @@ iD.ui.PresetGrid = function(context, entity) {
|
||||
.style('max-height', '0px')
|
||||
.style('padding-top', '0px')
|
||||
.style('padding-bottom', '0px')
|
||||
.each('end', function() {
|
||||
shown.remove();
|
||||
});
|
||||
|
||||
.remove();
|
||||
|
||||
if (shown.datum() === entity && shown.classed(klass)) return;
|
||||
shownIndex = Array.prototype.indexOf.call(shown.node().parentNode.childNodes, shown.node());
|
||||
@@ -203,50 +199,29 @@ iD.ui.PresetGrid = function(context, entity) {
|
||||
.style('max-height', '0px')
|
||||
.style('padding-top', '0px')
|
||||
.style('padding-bottom', '0px')
|
||||
.style('opacity', '0')
|
||||
.transition()
|
||||
.duration(200)
|
||||
.style('padding-top', '10px')
|
||||
.style('padding-bottom', '20px')
|
||||
.style('max-height', '200px');
|
||||
.style('max-height', '200px')
|
||||
.style('opacity', '1');
|
||||
|
||||
presetinspect.append('h2')
|
||||
presetinspect.append('h3')
|
||||
.text(d.name());
|
||||
|
||||
var description = presetinspect.append('p');
|
||||
var link = presetinspect.append('a');
|
||||
var tag = {key: Object.keys(d.tags)[0]};
|
||||
|
||||
var params = {},
|
||||
locale = iD.detect().locale.split('-')[0] || 'en';
|
||||
|
||||
params.key = Object.keys(d.tags)[0];
|
||||
if (d.tags[params.key] !== '*') {
|
||||
params.value = d.tags[params.key];
|
||||
if (d.tags[tag.key] !== '*') {
|
||||
tag.value = d.tags[tag.key];
|
||||
}
|
||||
|
||||
taginfo.docs(params, function(err, data) {
|
||||
if (err) return description.text(t('inspector.no_documentation_combination'));
|
||||
var doc = _.find(data, function(d) { return d.lang === locale; }) ||
|
||||
_.find(data, function(d) { return d.lang === 'en'; });
|
||||
if (doc) {
|
||||
description
|
||||
.text(doc.description);
|
||||
link
|
||||
.attr('href', 'http://wiki.openstreetmap.org/wiki/' +
|
||||
encodeURIComponent(doc.title))
|
||||
.text(t('inspector.reference'));
|
||||
}
|
||||
});
|
||||
|
||||
presetinspect.selectAll('*')
|
||||
.style('opacity','0')
|
||||
.transition()
|
||||
.delay(100)
|
||||
.duration(200)
|
||||
.style('opacity','1');
|
||||
presetinspect.append('div')
|
||||
.call(iD.ui.TagReference(entity, tag));
|
||||
}
|
||||
|
||||
if (selection.node() === grid.node()) {
|
||||
show_more
|
||||
showMore
|
||||
.style('display', (selection.data()[0].length > limit) ? 'block' : 'none');
|
||||
}
|
||||
|
||||
@@ -256,20 +231,21 @@ iD.ui.PresetGrid = function(context, entity) {
|
||||
.selectAll('div.grid-entry-wrap')
|
||||
.data(function(d) { return d.slice(0, limit); }, name);
|
||||
|
||||
entries.exit().remove();
|
||||
entries.exit()
|
||||
.remove();
|
||||
|
||||
var entered = entries.enter()
|
||||
.append('div')
|
||||
.attr('class','grid-button-wrap col4 grid-entry-wrap')
|
||||
.classed('category', function(d) { return !!d.members; })
|
||||
.classed('current', function(d) { return d === preset; })
|
||||
.append('button')
|
||||
.attr('class', 'grid-entry')
|
||||
.on('click', choose);
|
||||
.append('button')
|
||||
.attr('class', 'grid-entry')
|
||||
.on('click', choose);
|
||||
|
||||
entered.style('opacity', 0)
|
||||
.transition()
|
||||
.style('opacity', 1);
|
||||
.transition()
|
||||
.style('opacity', 1);
|
||||
|
||||
entered.append('div')
|
||||
.attr('class', presetClass);
|
||||
@@ -286,15 +262,13 @@ iD.ui.PresetGrid = function(context, entity) {
|
||||
.attr('class','label')
|
||||
.text(name);
|
||||
|
||||
entered.filter(function(d) {
|
||||
return !d.members;
|
||||
})
|
||||
entered.filter(function(d) { return !d.members; })
|
||||
.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.attr('class', 'preset-help')
|
||||
.attr('class', 'tag-reference-button')
|
||||
.on('click', helpClick, selection)
|
||||
.append('span')
|
||||
.attr('class', 'icon inspect');
|
||||
.attr('class', 'icon inspect light');
|
||||
|
||||
entries.order();
|
||||
}
|
||||
|
||||
@@ -6,21 +6,29 @@ iD.ui.Restore = function(context) {
|
||||
var modal = iD.ui.modal(selection);
|
||||
|
||||
modal.select('.modal')
|
||||
.attr('class', 'modal-splash modal');
|
||||
.attr('class', 'modal fillL col6');
|
||||
|
||||
var introModal = modal.select('.content');
|
||||
|
||||
introModal.attr('class','cf');
|
||||
|
||||
introModal.append('div')
|
||||
.attr('class', 'modal-section header')
|
||||
.append('h3')
|
||||
.text(t('restore.description'));
|
||||
.text(t('restore.heading'));
|
||||
|
||||
introModal.append('div')
|
||||
.attr('class','modal-section')
|
||||
.append('p')
|
||||
.text(t('restore.description'));
|
||||
|
||||
|
||||
var buttonWrap = introModal.append('div')
|
||||
.attr('class', 'modal-section cf col12');
|
||||
.attr('class', 'modal-section col12');
|
||||
|
||||
var buttons = buttonWrap
|
||||
.append('div')
|
||||
.attr('class', 'button-wrap joined col6');
|
||||
.attr('class', 'button-wrap joined col4');
|
||||
|
||||
var restore = buttons.append('button')
|
||||
.attr('class', 'save action button col6')
|
||||
|
||||
@@ -2,6 +2,9 @@ iD.ui.SourceSwitch = function(context) {
|
||||
function click() {
|
||||
d3.event.preventDefault();
|
||||
|
||||
if (context.history().hasChanges() &&
|
||||
!window.confirm(t('source_switch.lose_changes'))) return;
|
||||
|
||||
var live = d3.select(this).classed('live');
|
||||
|
||||
context.connection()
|
||||
|
||||
@@ -15,5 +15,5 @@ iD.ui.Spinner = function(context) {
|
||||
img.transition()
|
||||
.style('opacity', 0);
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -26,26 +26,18 @@ iD.ui.TagEditor = function(context, entity) {
|
||||
var messagewrap = selection.append('div')
|
||||
.attr('class', 'header fillL cf');
|
||||
|
||||
var back = messagewrap.append('button')
|
||||
.attr('class', 'preset-reset fl ' + geometry)
|
||||
messagewrap.append('button')
|
||||
.attr('class', 'preset-reset fl ')
|
||||
.on('click', function() {
|
||||
event.choose(preset);
|
||||
});
|
||||
|
||||
var icon = preset.icon || (geometry === 'line' ? 'other-line' : 'marker-stroked');
|
||||
|
||||
back.append('div')
|
||||
.attr('class', 'col12')
|
||||
.append('span')
|
||||
.attr('class', 'preset-icon icon feature-' + icon);
|
||||
|
||||
back.append('div')
|
||||
.attr('class', 'col12')
|
||||
})
|
||||
.append('span')
|
||||
.attr('class', 'icon back');
|
||||
|
||||
var icon = preset.icon || (geometry === 'line' ? 'other-line' : 'marker-stroked');
|
||||
|
||||
messagewrap.append('h3')
|
||||
.attr('class', 'inspector-inner fl')
|
||||
.attr('class', 'inspector-inner')
|
||||
.text(t('inspector.editing_feature', { feature: preset.name() }));
|
||||
|
||||
messagewrap.append('button')
|
||||
@@ -57,8 +49,14 @@ iD.ui.TagEditor = function(context, entity) {
|
||||
var editorwrap = selection.append('div')
|
||||
.attr('class', 'tag-wrap inspector-body fillL2 inspector-body-' + geometry);
|
||||
|
||||
presetUI = iD.ui.preset(context, entity)
|
||||
.preset(preset)
|
||||
editorwrap.append('div')
|
||||
.attr('class', 'col12 inspector-inner preset-icon-wrap fillL3')
|
||||
.append('div')
|
||||
.attr('class','fillL')
|
||||
.append('span')
|
||||
.attr('class', geometry + ' preset-icon icon feature-' + icon);
|
||||
|
||||
presetUI = iD.ui.preset(context, entity, preset)
|
||||
.on('change', changeTags)
|
||||
.on('close', event.close);
|
||||
|
||||
@@ -75,7 +73,7 @@ iD.ui.TagEditor = function(context, entity) {
|
||||
|
||||
if (!entity.isNew()) {
|
||||
tageditorpreset.append('div')
|
||||
.attr('class', 'view-on-osm')
|
||||
.attr('class', 'col12 inspector-inner')
|
||||
.append('a')
|
||||
.attr('href', 'http://www.openstreetmap.org/browse/' + entity.type + '/' + entity.osmId())
|
||||
.attr('target', '_blank')
|
||||
|
||||
@@ -1,50 +1,64 @@
|
||||
iD.ui.tagReference = function(selection) {
|
||||
selection.each(function() {
|
||||
function g(x) { return function(d) { return d[x]; }; }
|
||||
var selection = d3.select(this);
|
||||
var header = selection.append('div')
|
||||
.attr('class','modal-section fillL header')
|
||||
.append('h3');
|
||||
iD.ui.TagReference = function(entity, tag) {
|
||||
var taginfo = iD.taginfo();
|
||||
|
||||
header.selectAll('span.icon')
|
||||
.data(g('types'))
|
||||
.enter()
|
||||
.append('span')
|
||||
.attr('title', function(d) {
|
||||
return t('tag_reference.used_with', {type: d});
|
||||
})
|
||||
.attr('class', function(d) {
|
||||
return 'icon big icon-pre-text big-' + d;
|
||||
function findLocal(docs) {
|
||||
var locale = iD.detect().locale.toLowerCase(),
|
||||
localized;
|
||||
|
||||
localized = _.find(docs, function(d) {
|
||||
return d.lang.toLowerCase() === locale;
|
||||
});
|
||||
if (localized) return localized;
|
||||
|
||||
// try the non-regional version of a language, like
|
||||
// 'en' if the language is 'en-US'
|
||||
if (locale.indexOf('-') !== -1) {
|
||||
var first = locale.split('-')[0];
|
||||
localized = _.find(docs, function(d) {
|
||||
return d.lang.toLowerCase() === first;
|
||||
});
|
||||
header.append('span')
|
||||
.text(g('title'));
|
||||
|
||||
var referenceBody = selection.append('div')
|
||||
.attr('class','modal-section fillL2');
|
||||
|
||||
referenceBody
|
||||
.append('h4')
|
||||
.text(t('tag_reference.description'));
|
||||
|
||||
if (selection.datum().image) {
|
||||
referenceBody
|
||||
.append('img')
|
||||
.attr('class', 'wiki-image')
|
||||
.attr('src', selection.datum().image.image_url);
|
||||
if (localized) return localized;
|
||||
}
|
||||
|
||||
referenceBody
|
||||
.append('p')
|
||||
.text(g('description'));
|
||||
// finally fall back to english
|
||||
return _.find(docs, function(d) {
|
||||
return d.lang.toLowerCase() === 'en';
|
||||
});
|
||||
}
|
||||
|
||||
referenceBody
|
||||
.append('a')
|
||||
.attr('target', '_blank')
|
||||
.attr('href', function(d) {
|
||||
return 'http://wiki.openstreetmap.org/wiki/' + d.title;
|
||||
})
|
||||
.text(function(d) {
|
||||
return t('tag_reference.on_wiki', {tag: d.title});
|
||||
});
|
||||
});
|
||||
return function(selection) {
|
||||
selection.html('');
|
||||
|
||||
selection.classed('cf', true);
|
||||
|
||||
taginfo.docs(tag, function(err, docs) {
|
||||
if (!err && docs) {
|
||||
docs = findLocal(docs);
|
||||
}
|
||||
|
||||
if (!docs || !docs.description) {
|
||||
return selection.text(t('inspector.no_documentation_key'));
|
||||
}
|
||||
|
||||
var referenceBody = selection.append('div')
|
||||
.attr('class','tag-reference-wrap');
|
||||
|
||||
if (docs.image && docs.image.thumb_url_prefix) {
|
||||
referenceBody
|
||||
.append('img')
|
||||
.attr('class', 'wiki-image')
|
||||
.attr('src', docs.image.thumb_url_prefix + "100" + docs.image.thumb_url_suffix);
|
||||
}
|
||||
|
||||
referenceBody
|
||||
.append('p')
|
||||
.text(docs.description);
|
||||
|
||||
referenceBody
|
||||
.append('a')
|
||||
.attr('target', '_blank')
|
||||
.attr('href', 'http://wiki.openstreetmap.org/wiki/' + docs.title)
|
||||
.text(t('inspector.reference'));
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
iD.ui.Taglist = function(context, entity) {
|
||||
var event = d3.dispatch('change'),
|
||||
taginfo = iD.taginfo(),
|
||||
initial = false,
|
||||
collapsebutton,
|
||||
list;
|
||||
|
||||
@@ -26,12 +25,8 @@ iD.ui.Taglist = function(context, entity) {
|
||||
.attr('class', 'tag-list');
|
||||
|
||||
var newTag = wrap.append('button')
|
||||
.attr('class', 'add-tag col6');
|
||||
|
||||
newTag.on('click', function() {
|
||||
addTag();
|
||||
focusNewKey();
|
||||
});
|
||||
.attr('class', 'add-tag col6')
|
||||
.on('click', addTag);
|
||||
|
||||
newTag.append('span')
|
||||
.attr('class', 'icon plus');
|
||||
@@ -86,101 +81,30 @@ iD.ui.Taglist = function(context, entity) {
|
||||
|
||||
row.each(bindTypeahead);
|
||||
|
||||
var removeBtn = row.append('button')
|
||||
row.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.attr('class','remove minor')
|
||||
.on('click', removeTag);
|
||||
|
||||
removeBtn.append('span')
|
||||
.on('click', removeTag)
|
||||
.append('span')
|
||||
.attr('class', 'icon delete');
|
||||
|
||||
function findLocal(docs) {
|
||||
var locale = iD.detect().locale.toLowerCase(),
|
||||
localized;
|
||||
|
||||
localized = _.find(docs, function(d) {
|
||||
return d.lang.toLowerCase() === locale;
|
||||
});
|
||||
if (localized) return localized;
|
||||
|
||||
// try the non-regional version of a language, like
|
||||
// 'en' if the language is 'en-US'
|
||||
if (locale.indexOf('-') !== -1) {
|
||||
var first = locale.split('-')[0];
|
||||
localized = _.find(docs, function(d) {
|
||||
return d.lang.toLowerCase() === first;
|
||||
});
|
||||
if (localized) return localized;
|
||||
}
|
||||
|
||||
// finally fall back to english
|
||||
return _.find(docs, function(d) {
|
||||
return d.lang.toLowerCase() === 'en';
|
||||
});
|
||||
}
|
||||
|
||||
function keyValueReference(err, docs) {
|
||||
var local;
|
||||
if (!err && docs) {
|
||||
local = findLocal(docs);
|
||||
}
|
||||
if (local) {
|
||||
var types = [];
|
||||
if (local.on_area) types.push('area');
|
||||
if (local.on_node) types.push('point');
|
||||
if (local.on_way) types.push('line');
|
||||
local.types = types;
|
||||
iD.ui.modal(context.container())
|
||||
.select('.content')
|
||||
.datum(local)
|
||||
.call(iD.ui.tagReference);
|
||||
} else {
|
||||
iD.ui.flash(context.container())
|
||||
.select('.content')
|
||||
.append('h3')
|
||||
.text(t('inspector.no_documentation_combination'));
|
||||
}
|
||||
}
|
||||
|
||||
function keyReference(err, values, params) {
|
||||
if (!err && values.length) {
|
||||
iD.ui.modal(context.container())
|
||||
.select('.content')
|
||||
.datum({
|
||||
data: values,
|
||||
title: 'Key:' + params.key,
|
||||
geometry: params.geometry
|
||||
})
|
||||
.call(iD.ui.keyReference);
|
||||
} else {
|
||||
iD.ui.flash(context.container())
|
||||
.select('.content')
|
||||
.append('h3')
|
||||
.text(t('inspector.no_documentation_key'));
|
||||
}
|
||||
}
|
||||
|
||||
var helpBtn = row.append('button')
|
||||
row.append('button')
|
||||
.attr('tabindex', -1)
|
||||
.attr('class', 'tag-help minor')
|
||||
.on('click', function(d) {
|
||||
var params = _.extend({}, d, {
|
||||
geometry: entity.geometry(context.graph())
|
||||
});
|
||||
if (d.key && d.value) {
|
||||
taginfo.docs(params, keyValueReference);
|
||||
} else if (d.key) {
|
||||
taginfo.values(params, keyReference);
|
||||
}
|
||||
});
|
||||
.on('click', function(tag) {
|
||||
row.selectAll('div.tag-help')
|
||||
.style('display', 'none');
|
||||
|
||||
helpBtn.append('span')
|
||||
.attr('class', 'icon inspect');
|
||||
d3.select(d3.select(this).node().parentNode)
|
||||
.select('div.tag-help')
|
||||
.style('display', 'block')
|
||||
.call(iD.ui.TagReference(entity, {key: tag.key}));
|
||||
})
|
||||
.append('span')
|
||||
.attr('class', 'icon inspect light');
|
||||
|
||||
if (initial && tags.length === 1 &&
|
||||
tags[0].key === '' && tags[0].value === '') {
|
||||
focusNewKey();
|
||||
}
|
||||
row.append('div')
|
||||
.attr('class', 'tag-help');
|
||||
|
||||
return li;
|
||||
}
|
||||
@@ -190,7 +114,6 @@ iD.ui.Taglist = function(context, entity) {
|
||||
list.selectAll('li:last-child input.value').node() === this &&
|
||||
!d3.event.shiftKey) {
|
||||
addTag();
|
||||
focusNewKey();
|
||||
d3.event.preventDefault();
|
||||
}
|
||||
}
|
||||
@@ -198,8 +121,8 @@ iD.ui.Taglist = function(context, entity) {
|
||||
function bindTypeahead() {
|
||||
var geometry = entity.geometry(context.graph()),
|
||||
row = d3.select(this),
|
||||
key = row.selectAll('.key-wrap'),
|
||||
value = row.selectAll('.input-wrap-position');
|
||||
key = row.selectAll('input.key'),
|
||||
value = row.selectAll('input.value');
|
||||
|
||||
function sort(value, data) {
|
||||
var sameletter = [],
|
||||
@@ -214,40 +137,35 @@ iD.ui.Taglist = function(context, entity) {
|
||||
return sameletter.concat(other);
|
||||
}
|
||||
|
||||
var keyinput = key.select('input');
|
||||
key.call(d3.combobox()
|
||||
.fetcher(function(_, __, callback) {
|
||||
.fetcher(function(value, __, callback) {
|
||||
taginfo.keys({
|
||||
debounce: true,
|
||||
geometry: geometry,
|
||||
query: keyinput.property('value')
|
||||
query: value
|
||||
}, function(err, data) {
|
||||
if (!err) callback(sort(keyinput.property('value'), data));
|
||||
if (!err) callback(sort(value, data));
|
||||
});
|
||||
}));
|
||||
|
||||
var valueinput = value.select('input');
|
||||
value.call(d3.combobox()
|
||||
.fetcher(function(_, __, callback) {
|
||||
.fetcher(function(value, __, callback) {
|
||||
taginfo.values({
|
||||
debounce: true,
|
||||
key: keyinput.property('value'),
|
||||
key: key.property('value'),
|
||||
geometry: geometry,
|
||||
query: valueinput.property('value')
|
||||
query: value
|
||||
}, function(err, data) {
|
||||
if (!err) callback(sort(valueinput.property('value'), data));
|
||||
if (!err) callback(sort(value, data));
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
function focusNewKey() {
|
||||
list.selectAll('li:last-child input.key').node().focus();
|
||||
}
|
||||
|
||||
function addTag() {
|
||||
var tags = taglist.tags();
|
||||
tags[''] = '';
|
||||
drawTags(tags);
|
||||
list.selectAll('li:last-child input.key').node().focus();
|
||||
}
|
||||
|
||||
function removeTag(d) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
d3.combobox = function() {
|
||||
var event = d3.dispatch('accept'),
|
||||
id = d3.combobox.id ++,
|
||||
container, input, shown = false, data = [];
|
||||
data = [];
|
||||
|
||||
var fetcher = function(val, data, cb) {
|
||||
cb(data.filter(function(d) {
|
||||
@@ -12,22 +12,28 @@ d3.combobox = function() {
|
||||
}));
|
||||
};
|
||||
|
||||
var typeahead = function(selection) {
|
||||
var idx = -1;
|
||||
input = selection.select('input').classed('combobox-input', true);
|
||||
var typeahead = function(input) {
|
||||
var idx = -1, container, shown = false;
|
||||
|
||||
selection.append('div', selection.select('input'))
|
||||
.attr('class', 'combobox-carat')
|
||||
.on('mousedown', stop)
|
||||
.on('mousedown', function() {
|
||||
d3.event.preventDefault();
|
||||
mousedown();
|
||||
input
|
||||
.classed('combobox-input', true)
|
||||
.each(function() {
|
||||
var parent = this.parentNode,
|
||||
sibling = this.nextSibling;
|
||||
d3.select(parent)
|
||||
.insert('div', function() { return sibling; })
|
||||
.attr('class', 'combobox-carat')
|
||||
.on('mousedown', function () {
|
||||
// prevent the form element from blurring. it blurs
|
||||
// on mousedown
|
||||
d3.event.stopPropagation();
|
||||
d3.event.preventDefault();
|
||||
mousedown();
|
||||
});
|
||||
});
|
||||
|
||||
function updateSize() {
|
||||
var rect = selection.select('input')
|
||||
.node()
|
||||
.getBoundingClientRect();
|
||||
var rect = input.node().getBoundingClientRect();
|
||||
container.style({
|
||||
'left': rect.left + 'px',
|
||||
'width': rect.width + 'px',
|
||||
@@ -35,13 +41,6 @@ d3.combobox = function() {
|
||||
});
|
||||
}
|
||||
|
||||
function stop() {
|
||||
// prevent the form element from blurring. it blurs
|
||||
// on mousedown
|
||||
d3.event.stopPropagation();
|
||||
d3.event.preventDefault();
|
||||
}
|
||||
|
||||
function blur() {
|
||||
// hide the combobox whenever the input element
|
||||
// loses focus
|
||||
@@ -210,7 +209,7 @@ d3.combobox = function() {
|
||||
.order();
|
||||
}
|
||||
|
||||
fetcher.apply(selection, [value, data, render]);
|
||||
fetcher.apply(input, [value, data, render]);
|
||||
}
|
||||
|
||||
// select the choice given as d
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
d3.jsonp = function (url, callback) {
|
||||
function rand() {
|
||||
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
|
||||
c = '', i = -1;
|
||||
while (++i < 15) c += chars.charAt(Math.floor(Math.random() * 52));
|
||||
return c;
|
||||
}
|
||||
|
||||
function create(url) {
|
||||
var e = url.match(/callback=d3.jsonp.(\w+)/),
|
||||
c = e ? e[1] : rand();
|
||||
d3.jsonp[c] = function(data) {
|
||||
callback(data);
|
||||
delete d3.jsonp[c];
|
||||
script.remove();
|
||||
};
|
||||
return 'd3.jsonp.' + c;
|
||||
}
|
||||
|
||||
var cb = create(url),
|
||||
script = d3.select('head')
|
||||
.append('script')
|
||||
.attr('type', 'text/javascript')
|
||||
.attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
|
||||
};
|
||||
@@ -29,5 +29,8 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": "~0.8.20"
|
||||
},
|
||||
"dependencies": {
|
||||
"marked": "~0.2.8"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
<script src='../js/lib/d3.geo.tile.js'></script>
|
||||
<script src='../js/lib/d3.size.js'></script>
|
||||
<script src='../js/lib/d3.trigger.js'></script>
|
||||
<script src='../js/lib/d3.jsonp.js'></script>
|
||||
<script src='../js/lib/d3.keybinding.js'></script>
|
||||
<script src='../js/lib/d3.one.js'></script>
|
||||
<script src='../js/lib/d3-compat.js'></script>
|
||||
@@ -81,7 +82,6 @@
|
||||
<script src='../js/id/ui/splash.js'></script>
|
||||
<script src='../js/id/ui/restore.js'></script>
|
||||
<script src='../js/id/ui/tag_reference.js'></script>
|
||||
<script src='../js/id/ui/key_reference.js'></script>
|
||||
<script src='../js/id/ui/preset.js'></script>
|
||||
<script src='../js/id/ui/lasso.js'></script>
|
||||
<script src='../js/id/ui/source_switch.js'></script>
|
||||
@@ -184,6 +184,7 @@
|
||||
<script src="spec/actions/add_entity.js"></script>
|
||||
<script src="spec/actions/change_tags.js"></script>
|
||||
<script src='spec/actions/circularize.js'></script>
|
||||
<script src='spec/actions/orthogonalize.js'></script>
|
||||
<script src='spec/actions/connect.js'></script>
|
||||
<script src="spec/actions/delete_multiple.js"></script>
|
||||
<script src="spec/actions/delete_node.js"></script>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
describe("iD.actions.Orthogonalize", function () {
|
||||
var projection = d3.geo.mercator();
|
||||
|
||||
it("orthoganalizes a quad", function () {
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a', loc: [0, 0]}),
|
||||
'b': iD.Node({id: 'b', loc: [4, 0]}),
|
||||
'c': iD.Node({id: 'c', loc: [3, 2]}),
|
||||
'd': iD.Node({id: 'd', loc: [0, 2]}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
|
||||
});
|
||||
|
||||
graph = iD.actions.Orthogonalize('-', projection)(graph);
|
||||
|
||||
expect(graph.entity('-').nodes).to.have.length(5);
|
||||
});
|
||||
|
||||
it("orthoganalizes a triangle", function () {
|
||||
var graph = iD.Graph({
|
||||
'a': iD.Node({id: 'a', loc: [0, 0]}),
|
||||
'b': iD.Node({id: 'b', loc: [3, 0]}),
|
||||
'c': iD.Node({id: 'c', loc: [2, 2]}),
|
||||
'-': iD.Way({id: '-', nodes: ['a', 'b', 'c', 'a']})
|
||||
});
|
||||
|
||||
graph = iD.actions.Orthogonalize('-', projection)(graph);
|
||||
|
||||
expect(graph.entity('-').nodes).to.have.length(4);
|
||||
});
|
||||
});
|
||||