0001-geolocation-prefill-with-reverse-geocoding-5855.patch
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 |
('street-and-no', _('Street and number')), |
|
89 |
('city', _('City')), |
|
90 |
('country', _('Country')), |
|
91 |
] |
|
92 |
self.add(SingleSelectWidget, 'value', value=value.get('value'), |
|
93 |
options=geoloc_fields) |
|
77 | 94 | |
78 | 95 |
self.add(SubmitWidget, 'apply', value = _('Apply')) |
79 | 96 | |
... | ... | |
247 | 264 |
except: |
248 | 265 |
pass |
249 | 266 | |
267 |
elif t == 'geolocation': |
|
268 |
return None |
|
269 | ||
270 |
return None |
|
271 | ||
272 |
def get_prefill_attributes(self): |
|
273 |
t = self.prefill.get('type') |
|
274 |
if t == 'geolocation': |
|
275 |
return {'geolocation': self.prefill.get('value')} |
|
250 | 276 |
return None |
251 | 277 | |
252 | 278 |
def feed_session(self, value, display_value): |
... | ... | |
259 | 285 |
in_listing = True |
260 | 286 |
extra_attributes = [] |
261 | 287 |
prefill = {} |
288 |
prefill_kwargs = {} |
|
262 | 289 | |
263 | 290 |
def add_to_form(self, form, value = None): |
264 | 291 |
kwargs = {'required': self.required} |
... | ... | |
319 | 346 |
form.add(StringWidget, 'extra_css_class', title = _('Extra class for CSS styling'), |
320 | 347 |
value = self.extra_css_class, size = 30) |
321 | 348 |
form.add(PrefillSelectionWidget, 'prefill', title = _('Prefill'), |
322 |
value = self.prefill)
|
|
349 |
value=self.prefill, **self.prefill_kwargs)
|
|
323 | 350 | |
324 | 351 |
def check_admin_form(self, form): |
325 | 352 |
return |
... | ... | |
1376 | 1403 |
widget_class = MapWidget |
1377 | 1404 |
extra_attributes = ['initial_zoom', 'min_zoom', 'max_zoom', |
1378 | 1405 |
'default_position', 'init_with_geoloc'] |
1406 |
prefill_kwargs = {'map': True} |
|
1379 | 1407 | |
1380 | 1408 |
def fill_admin_form(self, form): |
1381 | 1409 |
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 |
street_and_number = data.address.road + ' ' + data.address.house_number; |
|
8 |
} else { |
|
9 |
street_and_number = data.address.road; |
|
10 |
} |
|
11 |
$('div[data-geolocation="street-and-no"] input').val(street_and_number); |
|
12 |
$('div[data-geolocation="city"] input').val(data.address.city || data.address.county); |
|
13 |
$('div[data-geolocation="country"] input').val(data.address.country); |
|
14 |
}); |
|
15 |
}); |
|
16 |
if ($('.qommon-map').length == 0) { |
|
17 |
/* if there's no map on the page, we do the geolocation without leaflet. */ |
|
18 |
if (navigator.geolocation) { |
|
19 |
$('div[data-geolocation] label').addClass('activity'); |
|
20 |
navigator.geolocation.getCurrentPosition( |
|
21 |
function (position) { |
|
22 |
$('div[data-geolocation] label').removeClass('activity'); |
|
23 |
var coords = {lat: position.coords.latitude, lng: position.coords.longitude}; |
|
24 |
$(document).trigger('set-geolocation', coords); |
|
25 |
}, |
|
26 |
function (error_msg) { |
|
27 |
$('div[data-geolocation] label').removeClass('activity'); |
|
28 |
}); |
|
29 |
} |
|
30 |
} |
|
31 |
}); |
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 © <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 |
- |