Projet

Général

Profil

0001-forms-sync-map-with-address-fields-27418.patch

Frédéric Péters, 13 avril 2019 19:57

Télécharger (7,73 ko)

Voir les différences:

Subject: [PATCH] forms: sync map with address fields (#27418)

 tests/test_api.py                             | 21 +++++++++++
 wcs/api.py                                    | 14 ++++++++
 wcs/qommon/form.py                            |  1 +
 wcs/qommon/static/js/qommon.geolocation.js    | 35 +++++++++++++++++++
 .../templates/qommon/forms/widgets/map.html   |  1 +
 wcs/urls.py                                   |  1 +
 6 files changed, 73 insertions(+)
tests/test_api.py
2384 2384
        pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
2385 2385
        resp = get_app(pub).get('/api/reverse-geocoding?lat=0&lon=0')
2386 2386
        assert urlopen.call_args[0][0] == 'http://reverse.example.net/?param=value&format=json&addressdetails=1&lat=0&lon=0&accept-language=en'
2387

  
2388

  
2389
def test_geocoding(pub):
2390
    with mock.patch('qommon.misc.urlopen') as urlopen:
2391
        urlopen.side_effect = lambda *args: StringIO(json.dumps([{'lat': 0, 'lon': 0}]))
2392
        get_app(pub).get('/api/geocoding', status=400)
2393
        resp = get_app(pub).get('/api/geocoding?q=test')
2394
        assert resp.content_type == 'application/json'
2395
        assert resp.body == json.dumps([{'lat': 0, 'lon': 0}])
2396
        assert urlopen.call_args[0][0] == 'http://nominatim.openstreetmap.org/search?format=json&q=test&accept-language=en'
2397

  
2398
        pub.site_options.add_section('options')
2399
        pub.site_options.set('options', 'nominatim_key', 'KEY')
2400
        pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
2401
        resp = get_app(pub).get('/api/geocoding?q=test')
2402
        assert urlopen.call_args[0][0] == 'http://nominatim.openstreetmap.org/search?key=KEY&format=json&q=test&accept-language=en'
2403

  
2404
        pub.site_options.set('options', 'geocoding_service_url', 'http://reverse.example.net/?param=value')
2405
        pub.site_options.write(open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w'))
2406
        resp = get_app(pub).get('/api/geocoding?q=test')
2407
        assert urlopen.call_args[0][0] == 'http://reverse.example.net/?param=value&format=json&q=test&accept-language=en'
wcs/api.py
810 810
    url += '&accept-language=%s' % (get_publisher().get_site_language() or 'en')
811 811
    return HttpResponse(misc.urlopen(url).read(), content_type='application/json')
812 812

  
813
def geocoding(request, *args, **kwargs):
814
    if not 'q' in request.GET:
815
        return HttpResponseBadRequest()
816
    q = request.GET['q']
817
    url = get_publisher().get_geocoding_service_url()
818
    if '?' in url:
819
        url += '&'
820
    else:
821
        url += '?'
822
    url += 'format=json&q=%s' % urllib.quote(q.encode('utf-8'))
823
    url += '&accept-language=%s' % (get_publisher().get_site_language() or 'en')
824
    return HttpResponse(misc.urlopen(url).read(), content_type='application/json')
825

  
826

  
813 827
def validate_expression(request, *args, **kwargs):
814 828
    expression = request.GET.get('expression')
815 829
    hint = {'klass': None, 'msg': ''}
wcs/qommon/form.py
2109 2109
        self.readonly = kwargs.pop('readonly', False)
2110 2110
        self.map_attributes = {}
2111 2111
        self.map_attributes.update(get_publisher().get_map_attributes())
2112
        self.sync_map_and_address_fields = get_publisher().has_site_option('sync-map-and-address-fields')
2112 2113
        for attribute in ('initial_zoom', 'min_zoom', 'max_zoom', 'init_with_geoloc'):
2113 2114
            if attribute in kwargs:
2114 2115
                self.map_attributes['data-' + attribute] = kwargs.pop(attribute)
wcs/qommon/static/js/qommon.geolocation.js
26 26

  
27 27
  $(document).on('set-geolocation', function(event, coords) {
28 28
    $.getJSON(WCS_ROOT_URL + '/api/reverse-geocoding?lat=' + coords.lat + '&lon=' + coords.lng, function(data) {
29
      unset_sync_callback()
29 30
      geoloc_prefill('house', data.address.house_number);
30 31
      var street = data.address.road;
31 32
      if (!street && data.address.pedestrian) {
......
41 42
      geoloc_prefill('postcode', data.address.postcode);
42 43
      geoloc_prefill('city', data.address.village || data.address.town || data.address.city || data.address.county);
43 44
      geoloc_prefill('country', data.address.country);
45
      set_sync_callback()
44 46
    });
45 47
  });
46 48
  if ($('.qommon-map').length == 0) {
......
62 64
      );
63 65
    }
64 66
  }
67

  
68
  function set_sync_callback() {
69
    var $map = $('.qommon-map');
70
    if (! $map.data('address-sync')) return;
71
    $('div[data-geolocation]').on('change', 'input[type=text], textarea, select', function(event) {
72
      var address = '';
73
      $(['number-and-street', 'house', 'road', 'postcode', 'city', 'country']).each(function(idx, elem) {
74
        var part = $('div[data-geolocation="' + elem + '"]').find('input, textarea, select').val();
75
        if (part) {
76
          address += part + ' ';
77
          if (elem == 'number-and-street' || elem == 'road' || elem == 'city') {
78
            address += ', ';
79
          }
80
        }
81
      });
82
      $.getJSON(WCS_ROOT_URL + '/api/geocoding?q=' + address, function(data) {
83
        if (data && $(data).length > 0) {
84
          var coords = {lat: data[0].lat, lon: data[0].lon};
85
          var map = $map[0].leaflet_map;
86
          map.flyTo(coords);
87
          if (map.marker === null) {
88
            map.marker = L.marker([0, 0]);
89
            map.marker.addTo(map);
90
          }
91
          map.marker.setLatLng(coords);
92
        }
93
      });
94
    });
95
  }
96
  function unset_sync_callback() {
97
    $('div[data-geolocation]').off('change', 'input[type=text], textarea, select');
98
  }
99
  set_sync_callback();
65 100
});
wcs/qommon/templates/qommon/forms/widgets/map.html
4 4
<input type="hidden" name="{{widget.name}}$latlng" {% if widget.value %}value="{{widget.value}}"{% endif %}>
5 5
<div id="map-{{widget.name}}" class="qommon-map"
6 6
  {% if widget.readonly %}data-readonly="true"{% endif %}
7
  {% if widget.sync_map_and_address_fields %}data-address-sync="true"{% endif %}
7 8
  {% for key, value in widget.map_attributes.items %}{{key}}="{{value}}" {% endfor %}
8 9
  {% if widget.initial_position %}
9 10
    data-init-lat="{{ widget.initial_position.lat }}"
wcs/urls.py
27 27
    url(r'^api/validate-condition$', api.validate_condition, name='api-validate-condition'),
28 28
    url(r'^api/validate-expression$', api.validate_expression, name='api-validate-expression'),
29 29
    url(r'^api/reverse-geocoding$', api.reverse_geocoding, name='api-reverse-geocoding'),
30
    url(r'^api/geocoding$', api.geocoding, name='api-geocoding'),
30 31

  
31 32
    # provide django.contrib.auth view names for compatibility with
32 33
    # templates created for classic django applications.
33
-