Added support for localization of address fields

This commit is contained in:
Christian Schwarz
2014-06-03 22:49:42 +02:00
parent 4f70731dfb
commit b3acd56bbb
8 changed files with 11211 additions and 39 deletions
+15 -2
View File
@@ -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
View File
@@ -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 */
+9
View File
@@ -0,0 +1,9 @@
[
{
"format": [["number", "street"], ["city", "postcode"]]
},
{
"countryCodes": ["AT", "CH", "DE"],
"format": [["street", "number"], ["postcode", "city"]]
}
]
+11054
View File
File diff suppressed because it is too large Load Diff
+6 -2
View File
@@ -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();
+30
View File
@@ -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
View File
@@ -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
+48
View File
@@ -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;
});
});
});