map field (#5668)
This commit is contained in:
parent
a508510700
commit
ec0000aa36
|
@ -15,6 +15,7 @@
|
|||
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import time
|
||||
import random
|
||||
import re
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
|
@ -1348,6 +1349,57 @@ class TableRowsField(WidgetField):
|
|||
register_field_class(TableRowsField)
|
||||
|
||||
|
||||
class MapField(WidgetField):
|
||||
key = 'map'
|
||||
description = N_('Map')
|
||||
|
||||
initial_zoom = None
|
||||
min_zoom = None
|
||||
max_zoom = None
|
||||
default_position = None
|
||||
init_with_geoloc = False
|
||||
|
||||
widget_class = MapWidget
|
||||
extra_attributes = ['initial_zoom', 'min_zoom', 'max_zoom',
|
||||
'default_position', 'init_with_geoloc']
|
||||
|
||||
def fill_admin_form(self, form):
|
||||
WidgetField.fill_admin_form(self, form)
|
||||
# 0: whole world, 9: wide area, 11: area, 13: town, 16: small road
|
||||
zoom_levels = [(None, '---'),
|
||||
('0', _('Whole world')),
|
||||
('9', _('Wide area')),
|
||||
('11', _('Area')),
|
||||
('13', _('Town')),
|
||||
('16', _('Small road')),
|
||||
('19', _('Ant')),]
|
||||
form.add(SingleSelectWidget, 'initial_zoom', title=_('Initial zoom level'),
|
||||
value=self.initial_zoom or '13', options=zoom_levels)
|
||||
form.add(SingleSelectWidget, 'min_zoom', title=_('Minimal zoom level'),
|
||||
value=self.min_zoom, options=zoom_levels, required=False)
|
||||
form.add(SingleSelectWidget, 'max_zoom', title=_('Maximal zoom level'),
|
||||
value=self.max_zoom, options=zoom_levels, required=False)
|
||||
form.add(MapWidget, 'default_position', title=_('Initial Position'),
|
||||
value=self.default_position, default_zoom='9', required=False)
|
||||
form.add(CheckboxWidget, 'init_with_geoloc',
|
||||
title=_('Initialize position using device geolocation'),
|
||||
value=self.init_with_geoloc, required=False)
|
||||
|
||||
def get_admin_attributes(self):
|
||||
return WidgetField.get_admin_attributes(self) + ['initial_zoom',
|
||||
'min_zoom', 'max_zoom', 'default_position',
|
||||
'init_with_geoloc']
|
||||
|
||||
def get_view_value(self, value):
|
||||
widget = self.widget_class('x%s' % random.random(), value, readonly=True)
|
||||
return widget.render_content()
|
||||
|
||||
def get_rst_view_value(self, value, indent=''):
|
||||
return indent + value
|
||||
|
||||
register_field_class(MapField)
|
||||
|
||||
|
||||
class RankedItemsField(WidgetField):
|
||||
key = 'ranked-items'
|
||||
description = N_('Ranked Items')
|
||||
|
|
|
@ -1873,3 +1873,38 @@ $(function() {
|
|||
self.value[fmt] = PASSWORD_FORMATS[fmt](pwd1)
|
||||
else:
|
||||
self.value = None
|
||||
|
||||
|
||||
class MapWidget(CompositeWidget):
|
||||
def __init__(self, name, value=None, **kwargs):
|
||||
CompositeWidget.__init__(self, name, value, **kwargs)
|
||||
self.add(HiddenWidget, 'latlng')
|
||||
self.readonly = kwargs.pop('readonly', False)
|
||||
self.kwargs = kwargs
|
||||
|
||||
def render_content(self):
|
||||
get_response().add_javascript(['qommon.map.js'])
|
||||
r = TemplateIO(html=True)
|
||||
for widget in self.get_widgets():
|
||||
r += widget.render()
|
||||
attrs = {
|
||||
'class': 'qommon-map',
|
||||
'id': 'map-%s' % self.name,
|
||||
}
|
||||
if self.value:
|
||||
attrs['data-init-lat'], attrs['data-init-lng'] = self.value.split(';')
|
||||
if self.readonly:
|
||||
attrs['data-readonly'] = 'true'
|
||||
for attribute in ('initial_zoom', 'min_zoom', 'max_zoom'):
|
||||
if attribute in self.kwargs:
|
||||
attrs['data-%s' % attribute] = self.kwargs.get(attribute)
|
||||
if self.kwargs.get('default_position'):
|
||||
attrs['data-def-lat'], attrs['data-def-lng'] = self.kwargs.get('default_position').split(';')
|
||||
if self.kwargs.get('init_with_geoloc'):
|
||||
attrs['data-init-with-geologc'] = 1
|
||||
r += htmltext('<div %s></div>' % ' '.join(['%s="%s"' % x for x in attrs.items()]))
|
||||
return r.getvalue()
|
||||
|
||||
def _parse(self, request):
|
||||
CompositeWidget._parse(self, request)
|
||||
self.value = self.get('latlng')
|
||||
|
|
|
@ -61,6 +61,10 @@ class HTTPResponse(quixote.http_response.HTTPResponse):
|
|||
self.javascript_scripts = []
|
||||
for script_name in script_names:
|
||||
if not script_name in self.javascript_scripts:
|
||||
if script_name == 'qommon.map.js':
|
||||
self.add_javascript(['jquery.js'])
|
||||
self.add_javascript(['../../leaflet/leaflet.js'])
|
||||
self.add_css_include('../../leaflet/leaflet.css')
|
||||
self.javascript_scripts.append(str(script_name))
|
||||
if script_name == 'afterjob.js':
|
||||
self.add_javascript_code('var QOMMON_ROOT_URL = "%s";\n' % \
|
||||
|
|
|
@ -389,3 +389,7 @@ ul.select2-results {
|
|||
outline: 0;
|
||||
border: 1px solid #aaa;
|
||||
}
|
||||
|
||||
div.qommon-map {
|
||||
height: 280px;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
$(function() {
|
||||
$('.qommon-map').each(function() {
|
||||
var map_options = Object();
|
||||
var initial_zoom = parseInt($(this).data('initial_zoom'));
|
||||
if (! isNaN(initial_zoom)) {
|
||||
map_options.zoom = initial_zoom;
|
||||
} else {
|
||||
map_options.zoom = 13;
|
||||
}
|
||||
var max_zoom = parseInt($(this).data('max_zoom'));
|
||||
if (! isNaN(max_zoom)) map_options.maxZoom = max_zoom;
|
||||
var min_zoom = parseInt($(this).data('min_zoom'));
|
||||
if (! isNaN(min_zoom)) map_options.minZoom = min_zoom;
|
||||
var map = L.map($(this).attr('id'), map_options);
|
||||
var hidden = $(this).prev();
|
||||
map.marker = null;
|
||||
var latlng;
|
||||
if ($(this).data('init-lat')) {
|
||||
latlng = [$(this).data('init-lat'), $(this).data('init-lng')]
|
||||
map.marker = L.marker(latlng);
|
||||
map.marker.addTo(map);
|
||||
} else if ($(this).data('def-lat')) {
|
||||
latlng = [$(this).data('def-lat'), $(this).data('def-lng')]
|
||||
} else {
|
||||
latlng = [50.84, 4.36];
|
||||
}
|
||||
map.setView(latlng, map_options.zoom);
|
||||
L.tileLayer(
|
||||
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||
{
|
||||
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>'
|
||||
}).addTo(map);
|
||||
if (! $(this).data('readonly')) {
|
||||
map.on('click', function(e) {
|
||||
if (map.marker === null) {
|
||||
map.marker = L.marker([0, 0]);
|
||||
map.marker.addTo(map);
|
||||
}
|
||||
map.marker.setLatLng(e.latlng);
|
||||
hidden.val(e.latlng.lat + ';' + e.latlng.lng);
|
||||
});
|
||||
}
|
||||
if ($(this).data('init-with-geoloc')) {
|
||||
map.on('locationfound', function(e) {
|
||||
hidden.val(e.latlng.lat + ';' + e.latlng.lng);
|
||||
map.setView(e.latlng, map_options.zoom);
|
||||
});
|
||||
map.locate({timeout: 1000, maximumAge: 60000});
|
||||
}
|
||||
});
|
||||
});
|
|
@ -359,6 +359,10 @@ class RootDirectory(Directory):
|
|||
dirname = os.path.join(get_publisher().data_dir, 'qommon')
|
||||
return StaticDirectory(dirname, follow_symlinks = True)
|
||||
|
||||
# maps /leaflet/ to the directory provided by the libjs-openlayers package
|
||||
if component == 'leaflet':
|
||||
return StaticDirectory('/usr/share/javascript/leaflet')
|
||||
|
||||
# is this a category ?
|
||||
try:
|
||||
category = Category.get_by_urlname(component)
|
||||
|
|
Loading…
Reference in New Issue