This commit is contained in:
Frédéric Péters 2014-10-10 19:19:25 +02:00
parent a508510700
commit ec0000aa36
6 changed files with 150 additions and 0 deletions

View File

@ -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')

View File

@ -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')

View File

@ -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' % \

View File

@ -389,3 +389,7 @@ ul.select2-results {
outline: 0;
border: 1px solid #aaa;
}
div.qommon-map {
height: 280px;
}

View File

@ -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 &copy; <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});
}
});
});

View File

@ -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)