Projet

Général

Profil

0001-geolocation-prefill-with-reverse-geocoding-5855.patch

Frédéric Péters, 04 novembre 2014 14:52

Télécharger (16,1 ko)

Voir les différences:

Subject: [PATCH] geolocation prefill, with reverse geocoding (#5855)

 wcs/api.py                                 | 13 ++++++-
 wcs/fields.py                              | 33 +++++++++++++++-
 wcs/forms/root.py                          |  1 +
 wcs/qommon/form.py                         | 17 ++++++---
 wcs/qommon/http_response.py                |  4 ++
 wcs/qommon/static/css/qommon.css           |  5 +++
 wcs/qommon/static/js/qommon.geolocation.js | 32 ++++++++++++++++
 wcs/qommon/static/js/qommon.map.js         | 61 +++++++++++++++++++-----------
 wcs/qommon/template.py                     |  2 +
 wcs/root.py                                |  5 ++-
 10 files changed, 140 insertions(+), 33 deletions(-)
 create mode 100644 wcs/qommon/static/js/qommon.geolocation.js
wcs/api.py
18 18
import hmac
19 19
import hashlib
20 20
import datetime
21
import urllib2
21 22

  
22
from quixote import get_request, get_publisher
23
from quixote import get_request, get_publisher, get_response
24
from quixote.directory import Directory
23 25
from qommon.errors import AccessForbiddenError
24 26

  
25 27
def get_user_from_api_query_string():
......
81 83
        raise AccessForbiddenError('missing email or NameID fields')
82 84

  
83 85
    return user
86

  
87

  
88
class ApiDirectory(Directory):
89
    _q_exports = [('reverse-geocoding', 'reverse_geocoding')]
90

  
91
    def reverse_geocoding(self):
92
        get_response().set_content_type('application/json')
93
        return urllib2.urlopen('http://nominatim.openstreetmap.org/reverse?format=json&zoom=18&addressdetails=1&'\
94
                + 'lat=%s&lon=%s' % (get_request().form['lat'], get_request().form['lon'])).read()
wcs/fields.py
47 47
        options = [('none', _('None')),
48 48
                ('string', _('String')),
49 49
                ('formula', _('Formula (Python)')),
50
                ('user', _('User Field'))]
50
                ('user', _('User Field')),
51
                ('geolocation', _('Geolocation')),]
52

  
53
        if kwargs.get('map'):
54
            options = [('none', _('None')), ('geolocation', _('Geolocation')),]
51 55

  
52 56
        self.add(SingleSelectWidget, 'type', options = options, value = value.get('type'))
53 57

  
......
74 78

  
75 79
            self.add(SingleSelectWidget, 'value', value = value.get('value'),
76 80
                    options = user_fields)
81
        elif self.value.get('type') == 'geolocation':
82
            if kwargs.get('map'):
83
                geoloc_fields = [('position', _('Position'))]
84
            else:
85
                geoloc_fields = [
86
                    ('house', _('Number')),
87
                    ('road', _('Street')),
88
                    ('number-and-street', _('Number and street')),
89
                    ('postcode', _('Post Code')),
90
                    ('city', _('City')),
91
                    ('country', _('Country')),
92
                    ]
93
            self.add(SingleSelectWidget, 'value', value=value.get('value'),
94
                    options=geoloc_fields)
77 95

  
78 96
        self.add(SubmitWidget, 'apply', value = _('Apply'))
79 97

  
......
247 265
            except:
248 266
                pass
249 267

  
268
        elif t == 'geolocation':
269
            return None
270

  
271
        return None
272

  
273
    def get_prefill_attributes(self):
274
        t = self.prefill.get('type')
275
        if t == 'geolocation':
276
            return {'geolocation': self.prefill.get('value')}
250 277
        return None
251 278

  
252 279
    def feed_session(self, value, display_value):
......
259 286
    in_listing = True
260 287
    extra_attributes = []
261 288
    prefill = {}
289
    prefill_kwargs = {}
262 290

  
263 291
    def add_to_form(self, form, value = None):
264 292
        kwargs = {'required': self.required}
......
319 347
        form.add(StringWidget, 'extra_css_class', title = _('Extra class for CSS styling'),
320 348
                value = self.extra_css_class, size = 30)
321 349
        form.add(PrefillSelectionWidget, 'prefill', title = _('Prefill'),
322
                value = self.prefill)
350
                value=self.prefill, **self.prefill_kwargs)
323 351

  
324 352
    def check_admin_form(self, form):
325 353
        return
......
1376 1404
    widget_class = MapWidget
1377 1405
    extra_attributes = ['initial_zoom', 'min_zoom', 'max_zoom',
1378 1406
            'default_position', 'init_with_geoloc']
1407
    prefill_kwargs = {'map': True}
1379 1408

  
1380 1409
    def fill_admin_form(self, form):
1381 1410
        WidgetField.fill_admin_form(self, form)
wcs/forms/root.py
259 259
                        form.get_widget('f%s' % k).set_message(
260 260
                                _('Value has been automatically prefilled.'))
261 261
                        form.get_widget('f%s' % k).prefilled = True
262
                    form.get_widget('f%s' % k).prefill_attributes = field.get_prefill_attributes()
262 263

  
263 264
                if not prefilled and form.get_widget('f%s' % k):
264 265
                    form.get_widget('f%s' % k).clear_error()
wcs/qommon/form.py
110 110
        classnames += ' widget-required'
111 111
    if self.is_prefilled():
112 112
        classnames += ' widget-prefilled'
113
    attributes = {}
113 114
    if hasattr(self, 'div_id') and self.div_id:
114
        r += htmltext('<div class="%s" id="%s" data-valuecontainerid="form_%s">') \
115
                % (classnames, self.div_id, self.name)
116
    else:
117
        r += htmltext('<div class="%s">') % classnames
115
        attributes['data-valuecontainerid'] = 'form_%s' % self.name
116
    if hasattr(self, 'prefill_attributes') and self.prefill_attributes:
117
        for k, v in self.prefill_attributes.items():
118
            attributes['data-' + k] = v
119
    if hasattr(self, 'div_id') and self.div_id:
120
        attributes['id'] = self.div_id
121
    attributes['class'] = classnames
122
    r += htmltext('<div %s>' % ' '.join(['%s="%s"' % x for x in attributes.items()]))
118 123
    r += self.render_title(self.get_title())
119 124
    classnames = 'content'
120 125
    if hasattr(self, 'content_extra_css_class') and self.content_extra_css_class:
......
1900 1905
        if self.readonly:
1901 1906
            attrs['data-readonly'] = 'true'
1902 1907
        for attribute in ('initial_zoom', 'min_zoom', 'max_zoom'):
1903
            if attribute in self.kwargs:
1908
            if attribute in self.kwargs and self.kwargs.get(attribute) is not None:
1904 1909
                attrs['data-%s' % attribute] = self.kwargs.get(attribute)
1905 1910
        if self.kwargs.get('default_position'):
1906 1911
            attrs['data-def-lat'], attrs['data-def-lng'] = self.kwargs.get('default_position').split(';')
1907 1912
        if self.kwargs.get('init_with_geoloc'):
1908
            attrs['data-init-with-geologc'] = 1
1913
            attrs['data-init-with-geoloc'] = 1
1909 1914
        r += htmltext('<div %s></div>' % ' '.join(['%s="%s"' % x for x in attrs.items()]))
1910 1915
        return r.getvalue()
1911 1916

  
wcs/qommon/http_response.py
71 71
                            get_publisher().get_application_static_files_root_url())
72 72
                if script_name == 'popup.js':
73 73
                    self.add_css_include('../js/smoothness/jquery-ui-1.10.0.custom.min.css')
74
                if script_name == 'qommon.geolocation.js':
75
                    self.add_javascript(['jquery.js'])
76
                    self.add_javascript_code('var WCS_ROOT_URL = "%s";\n' % \
77
                            get_publisher().get_frontoffice_url())
74 78

  
75 79
    def add_javascript_code(self, code):
76 80
        if not self.javascript_code_parts:
wcs/qommon/static/css/qommon.css
393 393
div.qommon-map {
394 394
	height: 280px;
395 395
}
396

  
397
label.activity {
398
	background: url(indicator.gif) no-repeat top right;
399
	padding-right: 30px;
400
}
wcs/qommon/static/js/qommon.geolocation.js
1
$(function() {
2
  $(document).on('set-geolocation', function(event, coords) {
3
    $.getJSON(WCS_ROOT_URL + '/api/reverse-geocoding?lat=' + coords.lat + '&lon=' + coords.lng, function(data) {
4
      $('div[data-geolocation="house"] input').val(data.address.house_number);
5
      $('div[data-geolocation="road"] input').val(data.address.road);
6
      if (data.address.road && data.address.house_number) {
7
        number_and_street = data.address.road + ' ' + data.address.house_number;
8
      } else {
9
        number_and_street = data.address.road;
10
      }
11
      $('div[data-geolocation="number-and-street"] input').val(number_and_street);
12
      $('div[data-geolocation="postcode"] input').val(data.address.postcode);
13
      $('div[data-geolocation="city"] input').val(data.address.town || data.address.city || data.address.county);
14
      $('div[data-geolocation="country"] input').val(data.address.country);
15
    });
16
  });
17
  if ($('.qommon-map').length == 0) {
18
    /* if there's no map on the page, we do the geolocation without leaflet. */
19
    if (navigator.geolocation) {
20
      $('div[data-geolocation] label').addClass('activity');
21
      navigator.geolocation.getCurrentPosition(
22
        function (position) {
23
          $('div[data-geolocation] label').removeClass('activity');
24
          var coords = {lat: position.coords.latitude, lng: position.coords.longitude};
25
          $(document).trigger('set-geolocation', coords);
26
        },
27
        function (error_msg) {
28
          $('div[data-geolocation] label').removeClass('activity');
29
        });
30
    }
31
  }
32
});
wcs/qommon/static/js/qommon.map.js
1 1
$(function() {
2 2
  $('.qommon-map').each(function() {
3
     var $map_widget = $(this);
3 4
     var map_options = Object();
4
     var initial_zoom = parseInt($(this).data('initial_zoom'));
5
     var initial_zoom = parseInt($map_widget.data('initial_zoom'));
5 6
     if (! isNaN(initial_zoom)) {
6 7
       map_options.zoom = initial_zoom;
7 8
     } else {
8 9
       map_options.zoom = 13;
9 10
     }
10
     var max_zoom = parseInt($(this).data('max_zoom'));
11
     var max_zoom = parseInt($map_widget.data('max_zoom'));
11 12
     if (! isNaN(max_zoom)) map_options.maxZoom = max_zoom;
12
     var min_zoom = parseInt($(this).data('min_zoom'));
13
     var min_zoom = parseInt($map_widget.data('min_zoom'));
13 14
     if (! isNaN(min_zoom)) map_options.minZoom = min_zoom;
14
     var map = L.map($(this).attr('id'), map_options);
15
     var map = L.map($map_widget.attr('id'), map_options);
15 16
     this.map_object = map;
16
     var hidden = $(this).prev();
17
     var hidden = $map_widget.prev();
17 18
     map.marker = null;
18 19
     var latlng;
19
     if ($(this).data('init-lat')) {
20
       latlng = [$(this).data('init-lat'), $(this).data('init-lng')]
20
     if ($map_widget.data('init-lat')) {
21
       latlng = [$map_widget.data('init-lat'), $map_widget.data('init-lng')]
21 22
       map.marker = L.marker(latlng);
22 23
       map.marker.addTo(map);
23
     } else if ($(this).data('def-lat')) {
24
       latlng = [$(this).data('def-lat'), $(this).data('def-lng')]
24
     } else if ($map_widget.data('def-lat')) {
25
       latlng = [$map_widget.data('def-lat'), $map_widget.data('def-lng')]
25 26
     } else {
26 27
       latlng = [50.84, 4.36];
27 28
     }
......
31 32
        {
32 33
                attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'
33 34
        }).addTo(map);
34
     if (! $(this).data('readonly')) {
35
     if (! $map_widget.data('readonly')) {
35 36
       map.on('click', function(e) {
36
         if (map.marker === null) {
37
           map.marker = L.marker([0, 0]);
38
           map.marker.addTo(map);
39
         }
40
         map.marker.setLatLng(e.latlng);
41
         hidden.val(e.latlng.lat + ';' + e.latlng.lng);
37
         $map_widget.trigger('set-geolocation', e.latlng);
42 38
       });
43 39
     }
44
     if ($(this).data('init-with-geoloc')) {
40
     $map_widget.on('set-geolocation', function(e, coords) {
41
       if (map.marker === null) {
42
         map.marker = L.marker([0, 0]);
43
         map.marker.addTo(map);
44
       }
45
       map.marker.setLatLng(coords);
46
       hidden.val(coords.lat + ';' + coords.lng);
47
     });
48
     position_prefil = $map_widget.parent().parent().data('geolocation') == 'position';
49
     if (! $map_widget.data('readonly') && ($map_widget.data('init-with-geoloc') || position_prefil)) {
45 50
       map.on('locationfound', function(e) {
46
         hidden.val(e.latlng.lat + ';' + e.latlng.lng);
47
         map.setView(e.latlng, map_options.zoom);
51
         $map_widget.parent().parent().find('label').removeClass('activity');
52
         if (map.marker === null) {
53
           hidden.val(e.latlng.lat + ';' + e.latlng.lng);
54
           map.setView(e.latlng, map_options.zoom);
55
           if (position_prefil) {
56
             map.setView(e.latlng, 16);
57
             $map_widget.trigger('set-geolocation', e.latlng);
58
           }
59
         }
60
       });
61
       map.on('locationerror', function(e) {
62
         $map_widget.parent().parent().find('label').removeClass('activity');
63
         $map_widget.parent().parent().find('label').after('<span class="geoloc">' + e.message + '</span>');
48 64
       });
49
       map.locate({timeout: 1000, maximumAge: 60000});
65
       $map_widget.parent().parent().find('label').addClass('activity')
66
       map.locate({timeout: 10000, maximumAge: 60000});
50 67
     }
51
     if ($(this).data('geojson-url')) {
52
       $.getJSON($(this).data('geojson-url'), function(data) {
68
     if ($map_widget.data('geojson-url')) {
69
       $.getJSON($map_widget.data('geojson-url'), function(data) {
53 70
         L.geoJson(data, {
54 71
           onEachFeature: function(feature, layer) {
55 72
             layer.on('click', function() {
wcs/qommon/template.py
294 294

  
295 295
    if 'rel="popup"' in body or 'rel="popup"' in kwargs.get('sidebar', ''):
296 296
        response.add_javascript(['jquery.js', 'jquery-ui.js', 'popup.js', 'widget_list.js'])
297
    if 'data-geolocation' in body:
298
        response.add_javascript(['qommon.geolocation.js'])
297 299

  
298 300
    onload = kwargs.get('onload')
299 301
    org_name = get_cfg('sp', {}).get('organization_name',
wcs/root.py
46 46
from formdef import FormDef
47 47
from anonylink import AnonymityLink
48 48
from roles import Role
49
from wcs.api import get_user_from_api_query_string
49
from wcs.api import get_user_from_api_query_string, ApiDirectory
50 50
from myspace import MyspaceDirectory
51 51

  
52 52

  
......
190 190
class RootDirectory(Directory):
191 191
    _q_exports = ['admin', 'backoffice', 'forms', 'login', 'logout', 'liberty', 'token', 'saml',
192 192
            'ident', 'register', 'afterjobs', 'themes', 'myspace', 'user', 'roles',
193
            'pages', ('tmp-upload', 'tmp_upload'), '__version__']
193
            'pages', ('tmp-upload', 'tmp_upload'), 'api', '__version__']
194 194

  
195
    api = ApiDirectory()
195 196
    themes = template.ThemesDirectory()
196 197
    myspace = MyspaceDirectory()
197 198
    pages = qommon.pages.PagesDirectory()
198
-