mirror of
https://github.com/FoggedLens/iD.git
synced 2026-04-21 19:26:41 +02:00
Added support for localization of address fields
This commit is contained in:
@@ -3,10 +3,12 @@ var fs = require('fs'),
|
||||
glob = require('glob'),
|
||||
YAML = require('js-yaml'),
|
||||
_ = require('./js/lib/lodash'),
|
||||
d3 = require('d3'),
|
||||
jsonschema = require('jsonschema'),
|
||||
fieldSchema = require('./data/presets/schema/field.json'),
|
||||
presetSchema = require('./data/presets/schema/preset.json'),
|
||||
suggestions = require('./data/name-suggestions.json');
|
||||
suggestions = require('./data/name-suggestions.json'),
|
||||
countries = require('./data/countries.json');
|
||||
|
||||
function readtxt(f) {
|
||||
return fs.readFileSync(f, 'utf8');
|
||||
@@ -180,6 +182,14 @@ function generatePresets() {
|
||||
};
|
||||
}
|
||||
|
||||
function updateCountryBounds() {
|
||||
_.forEach(countries.features, function (country) {
|
||||
country.properties.bounds = d3.geo.bounds(country);
|
||||
});
|
||||
|
||||
return countries;
|
||||
}
|
||||
|
||||
function validateCategoryPresets(categories, presets) {
|
||||
_.forEach(categories, function(category) {
|
||||
if (category.members) {
|
||||
@@ -220,6 +230,7 @@ validatePresetFields(presets.presets, fields);
|
||||
fs.writeFileSync('data/presets/categories.json', stringify(categories));
|
||||
fs.writeFileSync('data/presets/fields.json', stringify(fields));
|
||||
fs.writeFileSync('data/presets/presets.json', stringify(presets.presets));
|
||||
fs.writeFileSync('data/countries.json', stringify(updateCountryBounds(countries)));
|
||||
fs.writeFileSync('js/id/core/area_keys.js', '/* jshint -W109 */\niD.areaKeys = ' + stringify(presets.areaKeys) + ';');
|
||||
fs.writeFileSync('data/presets.yaml', YAML.dump({en: {presets: presets.presetsYaml}}));
|
||||
|
||||
@@ -245,5 +256,7 @@ fs.writeFileSync('data/data.js', 'iD.data = ' + stringify({
|
||||
operations: r('operations-sprite.json'),
|
||||
locales: r('locales.json'),
|
||||
en: read('dist/locales/en.json'),
|
||||
suggestions: r('name-suggestions.json')
|
||||
suggestions: r('name-suggestions.json'),
|
||||
addressFormats: r('address-formats.json'),
|
||||
countries: r('countries.json')
|
||||
}) + ';');
|
||||
|
||||
+22
-15
@@ -1497,38 +1497,45 @@ input[type=number] {
|
||||
|
||||
/* Preset form address */
|
||||
|
||||
.form-field .addr-housename {
|
||||
border: 0;
|
||||
.addr-row .addr-column[type="text"] {
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.addr-row:first-of-type .addr-column[type="text"] {
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
.addr-row .addr-column[type="text"]:first-of-type {
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.addr-column[type="text"] {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.addr-row:last-of-type .addr-column[type="text"]:first-of-type {
|
||||
border-radius: 0 0 0 4px;
|
||||
}
|
||||
|
||||
.addr-row:last-of-type .addr-column[type="text"]:last-of-type {
|
||||
border-radius: 0 0 4px 0;
|
||||
}
|
||||
|
||||
.form-field .addr-number {
|
||||
width: 33.3333%;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.form-field .addr-street {
|
||||
width: 66.6666%;
|
||||
border-top: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.form-field .addr-city {
|
||||
width: 66.6666%;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
border-radius: 0 0 0 4px;
|
||||
}
|
||||
|
||||
.form-field .addr-postcode {
|
||||
width: 33.3333%;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
border-radius: 0 0 4px 0;
|
||||
}
|
||||
|
||||
/* Restrictions editor */
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
[
|
||||
{
|
||||
"format": [["number", "street"], ["city", "postcode"]]
|
||||
},
|
||||
{
|
||||
"countryCodes": ["AT", "CH", "DE"],
|
||||
"format": [["street", "number"], ["postcode", "city"]]
|
||||
}
|
||||
]
|
||||
+11054
File diff suppressed because it is too large
Load Diff
+6
-2
@@ -18,7 +18,9 @@ iD.data = {
|
||||
path + 'data/operations-sprite.json',
|
||||
path + 'data/locales.json',
|
||||
path + 'dist/locales/en.json',
|
||||
path + 'data/name-suggestions.json'
|
||||
path + 'data/name-suggestions.json',
|
||||
path + 'data/address-formats.json',
|
||||
path + 'data/countries.json'
|
||||
], d3.json, function (err, data) {
|
||||
|
||||
iD.data = {
|
||||
@@ -37,7 +39,9 @@ iD.data = {
|
||||
operations: data[10],
|
||||
locales: data[11],
|
||||
en: data[12],
|
||||
suggestions: data[13]
|
||||
suggestions: data[13],
|
||||
addressFormats: data[14],
|
||||
countries: data[15]
|
||||
};
|
||||
|
||||
callback();
|
||||
|
||||
@@ -135,3 +135,33 @@ iD.geo.pathLength = function(path) {
|
||||
}
|
||||
return length;
|
||||
};
|
||||
|
||||
iD.geo.pointInFeature = function(point, feature) {
|
||||
if (feature.properties && feature.properties.bounds) {
|
||||
var bounds = feature.properties.bounds;
|
||||
|
||||
if (point[0] < bounds[0][0] || point[0] > bounds[1][0] || point[1] < bounds[0][1] || point[1] > bounds[1][1])
|
||||
return false;
|
||||
}
|
||||
|
||||
if (feature.geometry.type === 'Polygon') {
|
||||
return _.every(feature.geometry.coordinates, function (ring, i) {
|
||||
if (i === 0)
|
||||
return iD.geo.pointInPolygon(point, ring);
|
||||
|
||||
return !iD.geo.pointInPolygon(point, ring);
|
||||
});
|
||||
}
|
||||
else if (feature.geometry.type === 'MultiPolygon') {
|
||||
return _.some(feature.geometry.coordinates, function (polygon) {
|
||||
return _.every(polygon, function (ring, i) {
|
||||
if (i === 0)
|
||||
return iD.geo.pointInPolygon(point, ring);
|
||||
|
||||
return !iD.geo.pointInPolygon(point, ring);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
+27
-20
@@ -89,33 +89,40 @@ iD.ui.preset.address = function(field, context) {
|
||||
}
|
||||
|
||||
function address(selection) {
|
||||
var wrap = selection.selectAll('.preset-input-wrap')
|
||||
.data([0]);
|
||||
var wrap = selection.selectAll('.preset-input-wrap').data([0]),
|
||||
center = entity.extent(context.graph()).center(),
|
||||
countryCode,
|
||||
country,
|
||||
addressFormat;
|
||||
|
||||
country = _.find(iD.data.countries.features, function(f) {
|
||||
return iD.geo.pointInFeature(center, f);
|
||||
});
|
||||
|
||||
if (country)
|
||||
countryCode = country.properties.countryCode;
|
||||
|
||||
addressFormat = _.find(iD.data.addressFormats, function (a) {
|
||||
return a && a.countryCodes && _.contains(a.countryCodes, countryCode);
|
||||
}) || _.first(iD.data.addressFormats);
|
||||
|
||||
// Enter
|
||||
|
||||
var enter = wrap.enter().append('div')
|
||||
.attr('class', 'preset-input-wrap');
|
||||
|
||||
enter.append('input')
|
||||
enter.selectAll('div')
|
||||
.data(addressFormat.format)
|
||||
.enter()
|
||||
.append('div')
|
||||
.attr('class', 'addr-row')
|
||||
.selectAll('input')
|
||||
.data(function (d) { return d; })
|
||||
.enter()
|
||||
.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('placeholder', field.t('placeholders.number'))
|
||||
.attr('class', 'addr-number');
|
||||
|
||||
enter.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('placeholder', field.t('placeholders.street'))
|
||||
.attr('class', 'addr-street');
|
||||
|
||||
enter.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('placeholder', field.t('placeholders.city'))
|
||||
.attr('class', 'addr-city');
|
||||
|
||||
enter.append('input')
|
||||
.property('type', 'text')
|
||||
.attr('placeholder', field.t('placeholders.postcode'))
|
||||
.attr('class', 'addr-postcode');
|
||||
.attr('placeholder', function (d) { return field.t('placeholders.' + d); })
|
||||
.attr('class', function (d) { return 'addr-column addr-' + d; });
|
||||
|
||||
// Update
|
||||
|
||||
|
||||
@@ -223,4 +223,52 @@ describe('iD.geo', function() {
|
||||
expect(iD.geo.pathLength(path)).to.eql(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('.pointInFeature', function() {
|
||||
it('point should be in a polygon feature', function() {
|
||||
var feature = { geometry: { type: 'Polygon', coordinates: [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]] } };
|
||||
var point = [0.5, 0.5];
|
||||
expect(iD.geo.pointInFeature(point, feature)).to.be.true;
|
||||
});
|
||||
it('point should not be in a polygon feature with a hole', function() {
|
||||
var feature = { geometry: { type: 'Polygon', coordinates: [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]], [[0.1, 0.1], [0.1, 0.9], [0.9, 0.9], [0.9, 0.1], [0.1, 0.1]]] } };
|
||||
var point = [0.5, 0.5];
|
||||
expect(iD.geo.pointInFeature(point, feature)).to.be.false;
|
||||
});
|
||||
it('point should be in a polygon feature with a hole', function() {
|
||||
var feature = { geometry: { type: 'Polygon', coordinates: [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]], [[0.1, 0.1], [0.1, 0.9], [0.9, 0.9], [0.9, 0.1], [0.1, 0.1]]] } };
|
||||
var point = [0.05, 0.05];
|
||||
expect(iD.geo.pointInFeature(point, feature)).to.be.true;
|
||||
});
|
||||
it('point should be in a polygon feature with bounds', function() {
|
||||
var feature = { geometry: { type: 'Polygon', coordinates: [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]] }, properties: { bounds: [[0, 0], [1, 1]] } };
|
||||
var point = [0.5, 0.5];
|
||||
expect(iD.geo.pointInFeature(point, feature)).to.be.true;
|
||||
});
|
||||
it('point should not be in a polygon feature with bounds', function() {
|
||||
var feature = { geometry: { type: 'Polygon', coordinates: [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]] }, properties: { bounds: [[0, 0], [1, 1]] } };
|
||||
var point = [0.5, 1.5];
|
||||
expect(iD.geo.pointInFeature(point, feature)).to.be.false;
|
||||
});
|
||||
it('point should not be in a point feature', function() {
|
||||
var feature = { geometry: { type: 'Point', coordinates: [0, 0] } };
|
||||
var point = [0.5, 0.5];
|
||||
expect(iD.geo.pointInFeature(point, feature)).to.be.false;
|
||||
});
|
||||
it('point should be in a multipolygon feature', function() {
|
||||
var feature = { geometry: { type: 'MultiPolygon', coordinates: [[[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]], [[[2, 2], [2, 3], [3, 3], [3, 2], [2, 2]]]] } };
|
||||
var point = [0.5, 0.5];
|
||||
expect(iD.geo.pointInFeature(point, feature)).to.be.true;
|
||||
});
|
||||
it('point should be in a multipolygon feature in second polygon', function() {
|
||||
var feature = { geometry: { type: 'MultiPolygon', coordinates: [[[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]], [[[2, 2], [2, 3], [3, 3], [3, 2], [2, 2]]]] } };
|
||||
var point = [2.5, 2.5];
|
||||
expect(iD.geo.pointInFeature(point, feature)).to.be.true;
|
||||
});
|
||||
it('point should not be in a multipolygon feature', function() {
|
||||
var feature = { geometry: { type: 'MultiPolygon', coordinates: [[[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]], [[[2, 2], [2, 3], [3, 3], [3, 2], [2, 2]]]] } };
|
||||
var point = [0.5, 1.5];
|
||||
expect(iD.geo.pointInFeature(point, feature)).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user