summaryrefslogtreecommitdiff
path: root/chimere/widgets.py
diff options
context:
space:
mode:
Diffstat (limited to 'chimere/widgets.py')
-rw-r--r--chimere/widgets.py551
1 files changed, 373 insertions, 178 deletions
diff --git a/chimere/widgets.py b/chimere/widgets.py
index f501e23..2672ba0 100644
--- a/chimere/widgets.py
+++ b/chimere/widgets.py
@@ -20,34 +20,36 @@
"""
Extra widgets and fields
"""
-from django import conf
+
+from json import JSONEncoder
+
from django import forms
from django.conf import settings
from django.contrib.gis.db import models
from django.contrib.gis.geos import fromstr
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
-from django.forms.widgets import RadioInput, RadioFieldRenderer
-from django.utils.encoding import force_unicode
-from django.utils.html import conditional_escape
+from django.forms.widgets import RadioInput, RadioFieldRenderer, flatatt
+from django.utils.encoding import force_unicode, smart_unicode
+from django.utils.html import conditional_escape, escape
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _
from django.template.loader import render_to_string
import re
+
def getMapJS(area_name=''):
'''Variable initialization for drawing the map
'''
# projection, center and bounds definitions
- js = u"var epsg_display_projection = new OpenLayers.Projection('EPSG:%d')"\
- u";\n" % settings.CHIMERE_EPSG_DISPLAY_PROJECTION
- js += u"OpenLayers.ImgPath = '%schimere/img/';\n" % settings.STATIC_URL
- js += u"var epsg_projection = new OpenLayers.Projection('EPSG:%d');\n" % \
- settings.CHIMERE_EPSG_PROJECTION
- js += u"var centerLonLat = new OpenLayers.LonLat(%f,"\
- u"%f).transform(epsg_display_projection, epsg_projection);\n" % \
- settings.CHIMERE_DEFAULT_CENTER
+ js = u"var epsg_display_projection = 'EPSG:%d';\n" \
+ % settings.CHIMERE_EPSG_DISPLAY_PROJECTION
+ js += u"var epsg_projection = 'EPSG:%d';\n" % \
+ settings.CHIMERE_EPSG_PROJECTION
+ js += u"var centerLonLat = ol.proj.transform("\
+ u"[%f, %f], epsg_display_projection, epsg_projection);\n" % \
+ settings.CHIMERE_DEFAULT_CENTER
js += u"var media_path = '%s';\n" % settings.MEDIA_URL
js += u"var static_path = '%s';\n" % settings.STATIC_URL
js += u"var map_layer = %s;\n" % settings.CHIMERE_DEFAULT_MAP_LAYER
@@ -59,7 +61,8 @@ def getMapJS(area_name=''):
u"%s// !--></script>\n" % js
return js
-def get_map_layers(area_name=''):
+
+def get_map_layers(area_name='', get_area_zoom=False):
from chimere.models import Area
area = None
if area_name:
@@ -74,8 +77,9 @@ def get_map_layers(area_name=''):
pass
map_layers, default = [], None
if area and area.layers.count():
- map_layers = [[layer.name, layer.layer_code, False]
- for layer in area.layers.order_by('arealayers__order').all()]
+ map_layers = [
+ [layer.name, layer.layer_code, False, layer.extra_js_code or '']
+ for layer in area.layers.order_by('arealayers__order').all()]
def_layer = area.layers.filter(arealayers__default=True)
if def_layer.count():
def_layer = def_layer.all()[0]
@@ -87,34 +91,46 @@ def get_map_layers(area_name=''):
map_layers[0][2] = True
elif settings.CHIMERE_DEFAULT_MAP_LAYER:
map_layers = [(_(u"Default layer"), settings.CHIMERE_DEFAULT_MAP_LAYER,
- True)]
+ True, '')]
else:
- map_layers = [(u"Mapnik", "new OpenLayers.Layer.OSM.Mapnik('Mapnik')",
- True)]
- return map_layers, default
+ map_layers = [(u"Mapquest", """new ol.layer.Tile({
+ style: 'Road',
+ source: new ol.source.MapQuest({layer: 'osm'})
+})""", True, '')]
+ if not get_area_zoom:
+ return map_layers, default
+ if not area:
+ return map_layers, default, settings.CHIMERE_DEFAULT_ZOOM
+ zoom = "[%s]" % ",".join(area.getExtent())
+ return map_layers, default, zoom
+
class ChosenSelectWidget(forms.Select):
"""
Chosen select widget.
"""
class Media:
- js = ["%schosen/chosen/chosen.jquery.min.js" % settings.STATIC_URL,]
- css = {'all':
- ["%schosen/chosen/chosen.css" % settings.STATIC_URL,]
- }
+ js = ["%schosen/chosen/chosen.jquery.min.js" % settings.STATIC_URL]
+ css = {
+ 'all':
+ ["%schosen/chosen/chosen.css" % settings.STATIC_URL]
+ }
+
def render(self, *args, **kwargs):
if 'attrs' not in kwargs:
kwargs['attrs'] = {}
kwargs['attrs'].update({'class': 'chzn-select'})
rendered = super(ChosenSelectWidget, self).render(*args, **kwargs)
rendered += u"\n<script type='text/javascript'>\n"\
- u" $('#%s').chosen();\n"\
- u"</script>\n" % kwargs['attrs']['id']
+ u" $('#%s').chosen();\n"\
+ u"</script>\n" % kwargs['attrs']['id']
return mark_safe(rendered)
"""
JQuery UI button select widget.
"""
+
+
class ButtonRadioInput(RadioInput):
def render(self, name=None, value=None, attrs=None, choices=()):
name = name or self.name
@@ -127,13 +143,18 @@ class ButtonRadioInput(RadioInput):
choice_label = conditional_escape(force_unicode(self.choice_label))
return mark_safe(u'%s <label%s>%s</label>' % (self.tag(), label_for,
choice_label))
+
+
class ButtonRadioFieldRenderer(RadioFieldRenderer):
def __iter__(self):
for i, choice in enumerate(self.choices):
yield ButtonRadioInput(self.name, self.value, self.attrs.copy(),
choice, i)
+
def render(self):
return mark_safe(u'\n'.join([force_unicode(w) for w in self]))
+
+
class ButtonSelectWidget(forms.RadioSelect):
def __init__(self, *args, **kwargs):
self.renderer = ButtonRadioFieldRenderer
@@ -143,22 +164,36 @@ class ButtonSelectWidget(forms.RadioSelect):
rendered = "<div id='%s'>\n" % kwargs['attrs']['id']
rendered += super(ButtonSelectWidget, self).render(*args, **kwargs)
rendered += u"\n<script type='text/javascript'>\n"\
- u" $('#%s').buttonset();\n"\
- u"</script>\n</div>\n" % kwargs['attrs']['id']
+ u" $('#%s').buttonset();\n"\
+ u"</script>\n</div>\n" % kwargs['attrs']['id']
return mark_safe(rendered)
+
class ImporterChoicesWidget(forms.Select):
'''
Importer select widget.
'''
class Media:
- js = ["%schimere/js/importer_interface.js" % settings.STATIC_URL,]
+ js = ["%schimere/js/importer_interface.js" % settings.STATIC_URL]
+
+TINYMCE_JS, FULL_TINY_JS, ADMIN_TINY_JS = [], [], []
+
+if settings.TINYMCE_URL:
+ TINYMCE_JS = ["%stiny_mce.js" % settings.TINYMCE_URL]
+ FULL_TINY_JS = TINYMCE_JS[:] + \
+ ["%schimere/js/textareas.js" % settings.STATIC_URL]
+ ADMIN_TINY_JS = TINYMCE_JS[:] + \
+ ["%schimere/js/textareas_admin.js" % settings.STATIC_URL]
+
class TextareaWidgetBase(forms.Textarea):
"""
Manage the edition of a text using TinyMCE
"""
def render(self, *args, **kwargs):
+ if not TINYMCE_JS:
+ rendered = super(TextareaWidgetBase, self).render(*args, **kwargs)
+ return mark_safe(rendered)
if 'attrs' not in kwargs:
kwargs['attrs'] = {}
if 'class' not in kwargs['attrs']:
@@ -169,14 +204,19 @@ class TextareaWidgetBase(forms.Textarea):
rendered = super(TextareaWidgetBase, self).render(*args, **kwargs)
return mark_safe(rendered)
+
class FullTextareaWidget(TextareaWidgetBase):
"""
Manage the edition of a text using TinyMCE
"""
class Media:
- js = ["%stiny_mce.js" % settings.TINYMCE_URL]
+ js = TINYMCE_JS
def render(self, *args, **kwargs):
+ if not TINYMCE_JS:
+ rendered = super(FullTextareaWidget, self).render(*args, **kwargs)
+ return mark_safe(rendered)
+
if 'attrs' not in kwargs:
kwargs['attrs'] = {}
if 'class' not in kwargs['attrs']:
@@ -196,18 +236,19 @@ tinyMCE.init({
"""
return mark_safe(rendered)
+
class TextareaWidget(TextareaWidgetBase):
"""
Manage the edition of a text using TinyMCE
"""
class Media:
- js = ["%stiny_mce.js" % settings.TINYMCE_URL,
- "%schimere/js/textareas.js" % settings.STATIC_URL,]
+ js = FULL_TINY_JS
+
class TextareaAdminWidget(TextareaWidgetBase):
class Media:
- js = ["%stiny_mce.js" % settings.TINYMCE_URL,
- "%schimere/js/textareas_admin.js" % settings.STATIC_URL,]
+ js = ADMIN_TINY_JS
+
class DatePickerWidget(forms.TextInput):
"""
@@ -218,18 +259,85 @@ class DatePickerWidget(forms.TextInput):
def render(self, *args, **kwargs):
rendered = super(DatePickerWidget, self).render(*args, **kwargs)
rendered += u"\n<script type='text/javascript'>\n"\
- u" $(function() {$('#%s').datepicker({ dateFormat: 'yy-mm-dd' });});\n"\
- u"</script>\n" % kwargs['attrs']['id']
+ u" $(function() {$('#%s').datepicker("\
+ u"{ dateFormat: 'yy-mm-dd' });});\n"\
+ u"</script>\n" % kwargs['attrs']['id']
return mark_safe(rendered)
+
+class JQueryAutoComplete(forms.TextInput):
+ TEMPLATE = "chimere/blocks/JQueryAutoComplete.html"
+
+ def __init__(self, slug, options={}, attrs={}):
+ """
+ Source can be a list containing the autocomplete values or a
+ string containing the url used for the request.
+ """
+ self.options = None
+ self.attrs = {}
+ self.slug = slug
+ if len(options) > 0:
+ self.options = JSONEncoder().encode(options)
+ self.attrs.update(attrs)
+
+ def get_source(self):
+ # Strange... to be fixed
+ source = reverse('chimere:property-choices',
+ kwargs={'property_slug': self.slug})
+ return "'{}'".format(source)
+
+ def render(self, name, value=None, attrs=None):
+ attrs_hidden = self.build_attrs(attrs, name=name)
+ attrs_select = self.build_attrs(attrs)
+ selected_value, rendered_value = "", ""
+
+ if value:
+ val = escape(smart_unicode(value))
+ attrs_hidden['value'] = val
+ attrs_select['value'] = val
+ selected_value = val
+ if val:
+ from chimere.models import PropertyModelChoice
+ try:
+ attrs_select['value'] = unicode(
+ PropertyModelChoice.objects.get(
+ pk=value, propertymodel__slug=self.slug))
+ rendered_value = attrs_select['value']
+ except:
+ attrs_select['value'] = ""
+ if 'id' not in self.attrs:
+ attrs_hidden['id'] = 'id_%s' % name
+ attrs_select['id'] = 'id_select_%s' % name
+ if 'class' not in attrs_select:
+ attrs_select['class'] = 'autocomplete'
+ dct = {
+ 'attrs_select': flatatt(attrs_select),
+ 'attrs_hidden': flatatt(attrs_hidden),
+ 'field_id': name,
+ 'min_field_id': name.replace('_', ''),
+ 'options': self.options,
+ 'source': self.get_source(),
+ 'selected_value': selected_value,
+ 'rendered_value': rendered_value
+ }
+
+ return mark_safe(
+ render_to_string(self.TEMPLATE, dct))
+
+
class NominatimWidget(forms.TextInput):
class Media:
js = ["%schimere/js/nominatim-widget.js" % settings.STATIC_URL]
+
def render(self, name, value, attrs=None, area_name=''):
+ dct = {'id': name, 'nominatim_url': settings.NOMINATIM_URL,
+ 'label': _(u"Street, City, Country")}
+
tpl = u"""
<input type='hidden' name='nominatim_%(id)s_lat' id='nominatim_%(id)s_lat'/>
<input type='hidden' name='nominatim_%(id)s_lon' id='nominatim_%(id)s_lon'/>
-<input type='text' class='nominatim-widget' name='nominatim_%(id)s' id='nominatim_%(id)s' value=""/>
+<input type='text' class='nominatim-widget' name='nominatim_%(id)s'
+ id='nominatim_%(id)s' value=""/>
<label class='nominatim-label' id='nominatim_%(id)s_label'>&nbsp;</label>
<script type='text/javascript'>
var default_nominatim_lbl = "%(label)s";
@@ -239,21 +347,21 @@ $("#nominatim_%(id)s").click(function(){
$("#nominatim_%(id)s").val('');
});
</script>
-""" % {'id':name, 'nominatim_url':settings.NOMINATIM_URL,
- 'label':_(u"Street, City, Country")}
+""" % dct
return mark_safe(tpl)
+
class PointChooserWidget(forms.TextInput):
"""
Manage the edition of point on a map
"""
class Media:
css = {
- "all": settings.OSM_CSS_URLS + \
- ["%schimere/css/forms.css" % settings.STATIC_URL,]
+ "all": settings.MAP_CSS_URLS +
+ ["%schimere/css/forms.css" % settings.STATIC_URL]
}
- js = settings.OSM_JS_URLS + list(settings.JQUERY_JS_URLS) + \
- ["%schimere/js/jquery.chimere.js" % settings.STATIC_URL]
+ js = settings.MAP_JS_URLS + list(settings.JQUERY_JS_URLS) + \
+ ["%schimere/js/jquery.chimere.js" % settings.STATIC_URL]
def render(self, name, value, attrs=None, area_name='', initialized=True):
'''
@@ -273,9 +381,12 @@ class PointChooserWidget(forms.TextInput):
value = None
else:
value = None
- map_layers, default_area = get_map_layers(area_name)
- map_layers = [js for n, js, default in map_layers]
- #TODO: manage area
+ map_layers, default_area, zoom = get_map_layers(area_name,
+ get_area_zoom=True)
+ extra_js = [extra_js for n, js, default, extra_js in map_layers
+ if extra_js]
+ map_layers = [js for n, js, default, xtra_js in map_layers if js]
+ # TODO: manage area
return mark_safe(
render_to_string('chimere/blocks/live_coordinates.html',
{'lat': _("Latitude"),
@@ -285,18 +396,23 @@ class PointChooserWidget(forms.TextInput):
'name': name,
'val': val,
'initialized': initialized,
+ 'extra_js': "\n".join(extra_js),
'isvalue': bool(value),
- 'default_area': "true" if default_area else "false",
- }) % \
+ 'default_area': "true" if default_area
+ else "false",
+ }) %
(settings.STATIC_URL,
settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
settings.CHIMERE_EPSG_PROJECTION,
- settings.CHIMERE_DEFAULT_CENTER,
+ "[{}, {}]".format(settings.CHIMERE_DEFAULT_CENTER[0],
+ settings.CHIMERE_DEFAULT_CENTER[1]),
settings.CHIMERE_DEFAULT_ZOOM,
settings.STATIC_URL,
- ", ".join(map_layers)
+ ", ".join(map_layers),
+ zoom
)
- )
+ )
+
class HiddenPointChooserWidget(PointChooserWidget):
"""
@@ -307,13 +423,14 @@ class HiddenPointChooserWidget(PointChooserWidget):
kwargs['initialized'] = False
return super(HiddenPointChooserWidget, self).render(*args, **kwargs)
+
class PointField(models.PointField):
'''
Set the widget for the form field
'''
def __init__(self, *args, **kwargs):
self.widget = kwargs.pop('widget') if 'widget' in kwargs \
- else PointChooserWidget
+ else PointChooserWidget
return super(PointField, self).__init__(*args, **kwargs)
def formfield(self, **keys):
@@ -323,21 +440,23 @@ class PointField(models.PointField):
def clean(self, value, instance=None):
if len(value) != 2 and self.required:
- raise ValidationError(_("Invalid point"))
+ raise forms.ValidationError(_("Invalid point"))
return value
+
class RouteChooserWidget(forms.TextInput):
"""
Manage the edition of route on a map
"""
class Media:
- css = {"all": settings.OSM_CSS_URLS + \
- ["%schimere/css/forms.css" % settings.STATIC_URL,]
+ css = {
+ "all": settings.MAP_CSS_URLS +
+ ["%schimere/css/forms.css" % settings.STATIC_URL]
}
- js = settings.OSM_JS_URLS + list(settings.JQUERY_JS_URLS) + \
- ["%schimere/js/jquery.chimere.js" % settings.STATIC_URL,
- "%schimere/js/edit_route_map.js" % settings.STATIC_URL,
- "%schimere/js/base.js" % settings.STATIC_URL,]
+ js = settings.MAP_JS_URLS + list(settings.JQUERY_JS_URLS) + \
+ ["%schimere/js/jquery.chimere.js" % settings.STATIC_URL,
+ "%schimere/js/edit_route_map.js" % settings.STATIC_URL,
+ "%schimere/js/base.js" % settings.STATIC_URL]
def render(self, name, value, attrs=None, area_name='', routefile_id=None):
'''
@@ -345,67 +464,80 @@ class RouteChooserWidget(forms.TextInput):
'''
tpl = getMapJS(area_name)
map_layers, default_area = get_map_layers(area_name)
- map_layers = [js for nm, js, default in map_layers]
- js = """
+ extra_js = [extra_js for n, js, default, extra_js in map_layers
+ if extra_js]
+ map_layers = [js for nm, js, default, ext_js in map_layers]
+ js = u"""
var resolutions;
var zoomOffset;
var extra_url = "%s";
- OpenLayers.ImgPath = '%schimere/img/';
- var EPSG_DISPLAY_PROJECTION = epsg_display_projection = new OpenLayers.Projection('EPSG:%s');
- var EPSG_PROJECTION = epsg_projection = new OpenLayers.Projection('EPSG:%s');
- var CENTER_LONLAT = centerLonLat = new OpenLayers.LonLat%s.transform(epsg_display_projection, epsg_projection);
+ epsg_display_projection = 'EPSG:%s';
+ var EPSG_DISPLAY_PROJECTION = epsg_display_projection;
+ epsg_projection = 'EPSG:%s';
+ var EPSG_PROJECTION = epsg_projection;
+ centerLonLat = ol.proj.transform([%f %f],
+ epsg_display_projection, epsg_projection);
+ var CENTER_LONLAT = centerLonLat;
var DEFAULT_ZOOM = %s;
var chimere_init_options = {};
+ %s
chimere_init_options["map_layers"] = [%s];
chimere_init_options['dynamic_categories'] = false;
chimere_init_options['edition'] = true;
chimere_init_options['edition_type_is_route'] = true;
chimere_init_options["checked_categories"] = [];
- """ % (reverse("chimere:index"), settings.STATIC_URL,
- settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
- settings.CHIMERE_EPSG_PROJECTION, settings.CHIMERE_DEFAULT_CENTER,
- settings.CHIMERE_DEFAULT_ZOOM, ", ".join(map_layers))
+ """ % (reverse("chimere:index"),
+ settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
+ settings.CHIMERE_EPSG_PROJECTION,
+ settings.CHIMERE_DEFAULT_CENTER[0],
+ settings.CHIMERE_DEFAULT_CENTER[1],
+ settings.CHIMERE_DEFAULT_ZOOM,
+ u"\n".join(extra_js),
+ u", ".join(map_layers))
if default_area:
- js += "chimere_init_options['selected_map_layer'] = %d;\n" % \
+ js += u"chimere_init_options['selected_map_layer'] = %d;\n" % \
default_area
tpl = u"<script type='text/javascript'><!--\n"\
u"%s// !--></script>\n" % js
- #TODO: manage area
+ # TODO: manage area
help_create = ''
if not value:
help_create = u"<h3>%s</h3>\n"\
+ u"<p>%s</p>\n"\
+ u"<p>%s</p>\n"\
+ u"<p>%s</p>\n"\
+ u"<p>%s</p>\n"\
+ u"<p>%s</p>\n" % (
+ _(u"Creation mode"),
+ _(u"To start drawing the route click on the toggle "
+ u"button: \"Draw\"."),
+ _(u"Then click on the map to begin the drawing."),
+ _(u"You can add points by clicking again."),
+ _(u"To finish the drawing double click. When the drawing "
+ u"is finished you can edit it."),
+ _(u"While creating to undo a drawing click again on the "
+ u"toggle button \"Stop drawing\"."))
+ help_modify = u"<h3>%s</h3>\n"\
u"<p>%s</p>\n"\
u"<p>%s</p>\n"\
- u"<p>%s</p>\n"\
- u"<p>%s</p>\n"\
- u"<p>%s</p>\n" % (_(u"Creation mode"),
- _(u"To start drawing the route click on the toggle button: "\
- u"\"Draw\"."),
- _(u"Then click on the map to begin the drawing."),
- _(u"You can add points by clicking again."),
- _(u"To finish the drawing double click. When the drawing is "\
- u"finished you can edit it."),
- _(u"While creating to undo a drawing click again on the toggle "\
- u"button \"Stop drawing\"."))
- help_modify = u"<h3>%s</h3>\n"\
- u"<p>%s</p>\n"\
- u"<p>%s</p>\n"\
- u"<p>%s</p>\n" % (_(u"Modification mode"),
- _(u"To move a point click on it and drag it to the desired position."),
- _(u"To delete a point move the mouse cursor over it and press the "\
- u"\"d\" or \"Del\" key."),
- _(u"To add a point click in the middle of a segment and drag the new "\
- u"point to the desired position"))
+ u"<p>%s</p>\n" % (
+ _(u"Modification mode"),
+ _(u"To move a point click on it and drag it to the desired "
+ u"position."),
+ _(u"To delete a point move the mouse cursor over it and press "
+ u"the \"d\" or \"Del\" key."),
+ _(u"To add a point click in the middle of a segment and drag "
+ u"the new point to the desired position"))
if not value:
# upload a file
tpl += u"<script type='text/javascript'><!--\n"\
u" var error_msg = \"%s\";"\
- u"// --></script>" % (
- _(u"Give a name and set category before uploading a file."))
+ u"// --></script>" % \
+ _(u"Give a name and set category before uploading a file.")
tpl += u'<div id="upload"><a href="#" class="upload-button" '\
- u'onclick="uploadFile(error_msg);return false;">%s</a></div>' % (
- _(u"Upload a route file (GPX or KML)"))
+ u'onclick="uploadFile(error_msg);return false;">%s</a></div>' \
+ % (_(u"Upload a route file (GPX or KML)"))
tpl += u"\n<p id='draw-or'>%s</p>\n" % _(u"or")
tpl += u"<div id='draw-label'><div id='draw-toggle-off' "\
u"onclick='toggleDraw();'>\n"\
@@ -416,25 +548,26 @@ class RouteChooserWidget(forms.TextInput):
if value:
style = " style='display:block'"
tpl += u"\n<div class='help-route' id='help-route-modify'%s>%s</div>"\
- u"\n<hr class='spacer'/>\n"\
- u"<input type='hidden' name='%s' id='id_%s' value=\"%s\"/>\n"\
- u"<input type='hidden' name='associated_file_id' "\
- u"id='id_associated_file_id' value=\"%s\"/>\n" % (
- style, help_modify, name, name, value, routefile_id)
+ u"\n<hr class='spacer'/>\n"\
+ u"<input type='hidden' name='%s' id='id_%s' value=\"%s\"/>\n"\
+ u"<input type='hidden' name='associated_file_id' "\
+ u"id='id_associated_file_id' value=\"%s\"/>\n" % (
+ style, help_modify, name, name, value, routefile_id)
if value:
tpl += u"\n<div id='map_edit'></div>"
else:
tpl += "\n<div class='help-route' id='help-route-create'>%s</div>"\
% help_create
- tpl += u"\n<div id='map_edit'>\n"\
- u" <div class='map_button'>\n"\
- u" <a href='#' id='button-move-map' class='toggle-button "\
- u"toggle-button-active' onclick='toggleDrawOff();return false;'>%s"\
- u"</a>\n"\
- u"<a href='#' id='button-draw-map' class='toggle-button "\
- u"toggle-button-inactive' onclick='toggleDrawOn();return false;'>"\
- u"%s</a></div>\n"\
- u" </div>" % (_(u"Move on the map"), _(u"Draw"))
+ tpl += \
+ u"\n<div id='layerSwitcher'></div>\n<div id='map_edit'>\n"\
+ u" <div class='map_button'>\n"\
+ u" <a href='#' id='button-move-map' class='toggle-button "\
+ u"toggle-button-active' "\
+ u"onclick='toggleDrawOff();return false;'>%s</a>\n"\
+ u"<a href='#' id='button-draw-map' class='toggle-button "\
+ u"toggle-button-inactive' "\
+ u"onclick='toggleDrawOn();return false;'>%s</a></div>\n"\
+ u" </div>" % (_(u"Move on the map"), _(u"Draw"))
tpl += u"<script type='text/javascript'><!--\n"
if not value:
tpl += u"jQuery('#map_edit').hide();"
@@ -453,6 +586,7 @@ class RouteChooserWidget(forms.TextInput):
tpl += u"\n// --></script>\n"
return mark_safe(tpl)
+
class RouteField(models.LineStringField):
'''
Set the widget for the form field
@@ -462,18 +596,19 @@ class RouteField(models.LineStringField):
keys.update(defaults)
return super(RouteField, self).formfield(**keys)
+
class AreaWidget(forms.TextInput):
"""
Manage the edition of an area on the map
"""
class Media:
css = {
- "all": settings.OSM_CSS_URLS + \
- ["%schimere/css/forms.css" % settings.STATIC_URL,]
+ "all": settings.MAP_CSS_URLS +
+ ["%schimere/css/forms.css" % settings.STATIC_URL]
}
- js = settings.OSM_JS_URLS + [
- "%schimere/js/edit_area.js" % settings.STATIC_URL,
- "%schimere/js/base.js" % settings.STATIC_URL,]
+ js = settings.MAP_JS_URLS + [
+ "%schimere/js/edit_area.js" % settings.STATIC_URL,
+ "%schimere/js/base.js" % settings.STATIC_URL]
def get_bounding_box_from_value(self, value):
'''
@@ -483,7 +618,7 @@ class AreaWidget(forms.TextInput):
lower_right_lat, lower_right_lon = 0, 0
if not value:
return upper_left_lat, upper_left_lon, lower_right_lat, \
- lower_right_lon
+ lower_right_lon
if len(value) == 2:
upper_left = value[0]
lower_right = value[1]
@@ -497,7 +632,7 @@ class AreaWidget(forms.TextInput):
pass
if hasattr(lower_right, 'x') and hasattr(lower_right, 'y'):
lower_right_lon, lower_right_lat = lower_right.x, \
- lower_right.y
+ lower_right.y
elif len(lower_right) == 2:
lower_right_lon, lower_right_lat = lower_right
try:
@@ -512,29 +647,29 @@ class AreaWidget(forms.TextInput):
Render a map
"""
upper_left_lat, upper_left_lon, lower_right_lat, lower_right_lon = \
- self.get_bounding_box_from_value(value)
+ self.get_bounding_box_from_value(value)
tpl = getMapJS()
tpl += u"</div>\n"\
- u"<input type='hidden' name='upper_left_lat' id='upper_left_lat' "\
- u"value='%f'/>\n"\
- u"<input type='hidden' name='upper_left_lon' id='upper_left_lon' "\
- u"value='%f'/>\n"\
- u"<input type='hidden' name='lower_right_lat' id='lower_right_lat' "\
- u"value='%f'/>\n"\
- u"<input type='hidden' name='lower_right_lon' id='lower_right_lon' "\
- u"value='%f'/>\n" % (
- upper_left_lat, upper_left_lon, lower_right_lat, lower_right_lon)
+ u"<input type='hidden' name='upper_left_lat' id='upper_left_lat' "\
+ u"value='%f'/>\n"\
+ u"<input type='hidden' name='upper_left_lon' id='upper_left_lon' "\
+ u"value='%f'/>\n"\
+ u"<input type='hidden' name='lower_right_lat' id='lower_right_lat'"\
+ u" value='%f'/>\n"\
+ u"<input type='hidden' name='lower_right_lon' id='lower_right_lon'"\
+ u" value='%f'/>\n" % (
+ upper_left_lat, upper_left_lon, lower_right_lat,
+ lower_right_lon)
help_msg = _(u"Hold CTRL, click and drag to select area on the map")
tpl += u"<p class='help-osm'>%s</p>\n" % help_msg
tpl += u"<script type='text/javascript'>\n"
tpl += u"function init_map_form (){\ninit('map_edit_area');\n"
if value:
- tpl += u"var extent = new OpenLayers.Bounds(%f, %f, %f, %f);\n"\
- u"extent.transform(epsg_display_projection, epsg_projection);\n"\
- u"updateForm(extent);\n"\
- u"area_map.zoomToExtent(extent, true);\n"\
- u"area_map.zoomOut();" % (upper_left_lon, upper_left_lat,
- lower_right_lon, lower_right_lat)
+ tpl += u"extent = ol.proj.transformExtent([%f, %f, %f, %f], "\
+ u"epsg_display_projection, epsg_projection);\n"\
+ u"initArea(extent);\n" % (
+ upper_left_lon, upper_left_lat, lower_right_lon,
+ lower_right_lat)
tpl += u"}\n"
if initialized:
tpl += u"$(document).ready(function($) {init_map_form()});\n"
@@ -558,8 +693,61 @@ class AreaWidget(forms.TextInput):
values.append(value)
return values
-RE_XAPI = re.compile('(node|way)\[(.*=.*)\]\[bbox='\
- '(-*[0-9]*.[0-9]*,-*[0-9]*.[0-9]*,-*[0-9]*.[0-9]*,-*[0-9]*.[0-9]*)\]')
+
+class PolygonChooserWidget(forms.TextInput):
+ """
+ Manage the edition of polygon on a map
+ """
+ class Media:
+ css = {
+ "all": settings.MAP_CSS_URLS +
+ ["%schimere/css/forms.css" % settings.STATIC_URL]
+ }
+ js = settings.MAP_JS_URLS + list(settings.JQUERY_JS_URLS) + \
+ ["%schimere/js/jquery.chimere.js" % settings.STATIC_URL]
+
+ def render(self, name, value, attrs=None, area_name='', initialized=True):
+ val = ''
+ if value:
+ val = str(value)
+ map_layers, default_area, zoom = get_map_layers(area_name,
+ get_area_zoom=True)
+ extra_js = [extra_js for n, js, default, extra_js in map_layers
+ if extra_js]
+ map_layers = [js for n, js, default, ext_js in map_layers
+ if 'OpenLayers' not in js]
+ tpl = render_to_string(
+ 'chimere/blocks/polygon_edit.html',
+ {'name': name, 'val': val, 'initialized': initialized,
+ 'isvalue': bool(value),
+ 'default_area': "true" if default_area else "false",
+ 'value': value
+ }
+ )
+ return mark_safe(tpl.format(
+ static_url=settings.STATIC_URL,
+ display_projection=settings.CHIMERE_EPSG_DISPLAY_PROJECTION,
+ projection=settings.CHIMERE_EPSG_PROJECTION,
+ center=list(settings.CHIMERE_DEFAULT_CENTER),
+ zoom=zoom,
+ map_layers=u", ".join(map_layers),
+ extra_js=u"\n".join(extra_js),
+ ))
+
+
+class PolygonField(models.PolygonField):
+ '''
+ Set the widget for the form field
+ '''
+ def formfield(self, **keys):
+ defaults = {'widget': PolygonChooserWidget}
+ keys.update(defaults)
+ return super(PolygonField, self).formfield(**keys)
+
+RE_XAPI = re.compile(
+ '(node|way)\[(.*=.*)\]\[bbox='
+ '(-*[0-9]*.[0-9]*,-*[0-9]*.[0-9]*,-*[0-9]*.[0-9]*,-*[0-9]*.[0-9]*)\]')
+
class ImportFiltrWidget(AreaWidget):
"""
@@ -567,59 +755,61 @@ class ImportFiltrWidget(AreaWidget):
"""
class Media:
css = {
- "all": settings.OSM_CSS_URLS + \
- ["%schimere/css/forms.css" % settings.STATIC_URL,]
+ "all": settings.MAP_CSS_URLS +
+ ["%schimere/css/forms.css" % settings.STATIC_URL]
}
- js = settings.OSM_JS_URLS + [
- "%schimere/js/edit_area.js" % settings.STATIC_URL,
- "%schimere/js/base.js" % settings.STATIC_URL,]
+ js = settings.MAP_JS_URLS + [
+ "%schimere/js/edit_area.js" % settings.STATIC_URL,
+ "%schimere/js/base.js" % settings.STATIC_URL]
def render(self, name, value, attrs=None):
"""
Render a map
"""
tpl = super(ImportFiltrWidget, self).render(name, value, attrs,
- initialized=False)
+ initialized=False)
tpl += u"</div><hr class='spacer'/>"
- vals = {'lbl':_(u"Type:"), 'name':name, 'node':_(u"Node"),
- 'way':_(u"Way")}
+ vals = {'lbl': _(u"Type:"), 'name': name, 'node': _(u"Node"),
+ 'way': _(u"Way")}
vals['way_selected'] = ' checked="checked"'\
- if self.xapi_type == 'way' else ''
+ if self.xapi_type == 'way' else ''
vals['node_selected'] = ' checked="checked"'\
- if self.xapi_type == 'node' else ''
+ if self.xapi_type == 'node' else ''
tpl += u"<div class='input-osm'><label>%(lbl)s</label>"\
- u"<input type='radio' name='id_%(name)s_type' id='id_%(name)s_node'"\
- u" value='node'%(node_selected)s/> <label for='id_%(name)s_node'>"\
- u"%(node)s</label> <input type='radio' name='id_%(name)s_type' "\
- u"id='id_%(name)s_way' value='way'%(way_selected)s/> <label "\
- u"for='id_%(name)s_way'>%(way)s</label></div>" % vals
- help_msg = _(u"Enter an OSM \"tag=value\" string such as "\
- u"\"amenity=pub\". A list of common tag is available "\
- u"<a href='https://wiki.openstreetmap.org/wiki/Map_Features' "\
- u" target='_blank'>here</a>.")
+ u"<input type='radio' name='id_%(name)s_type' "\
+ u"id='id_%(name)s_node' value='node'%(node_selected)s/> "\
+ u"<label for='id_%(name)s_node'>"\
+ u"%(node)s</label> <input type='radio' name='id_%(name)s_type' "\
+ u"id='id_%(name)s_way' value='way'%(way_selected)s/> <label "\
+ u"for='id_%(name)s_way'>%(way)s</label></div>" % vals
+ help_msg = _(
+ u"Enter an OSM \"tag=value\" string such as "
+ u"\"amenity=pub\". A list of common tag is available "
+ u"<a href='https://wiki.openstreetmap.org/wiki/Map_Features' "
+ u" target='_blank'>here</a>.")
tpl += u"<p class='help-osm'>%s</p>\n" % help_msg
tpl += u"<div class='input-osm'><label for='id_%s_tag'>%s</label>"\
u"<input type='text' id='id_%s_tag' value=\"%s\"/></div>" % (
- name, _(u"Tag:"), name, self.xapi_tag)
+ name, _(u"Tag:"), name, self.xapi_tag)
tpl += u"<script type='text/javascript'>\n"
tpl += u"var default_xapi='%s';" % settings.CHIMERE_XAPI_URL
tpl += u'var msg_missing_area = "%s";' % \
- _(u"You have to select an area.")
+ _(u"You have to select an area.")
tpl += u'var msg_missing_type = "%s";' % \
- _(u"You have to select a type.")
+ _(u"You have to select a type.")
tpl += u'var msg_missing_filtr = "%s";' % \
- _(u"You have to insert a filter tag.")
+ _(u"You have to insert a filter tag.")
tpl += u"</script>\n"
- help_msg = _(u"If you change the above form don't forget to refresh "\
+ help_msg = _(u"If you change the above form don't forget to refresh "
u"before submit!")
tpl += u"<p class='help-osm errornote'>%s</p>\n" % help_msg
- help_msg = _(u"You can put a Folder name of the KML file to filter on "\
+ help_msg = _(u"You can put a Folder name of the KML file to filter on "
u"it.")
tpl += u"<p class='help-kml'>%s</p>\n" % help_msg
if not value:
value = ''
- tpl += u"<div><input type='text' id='id_%s' name='id_%s' "\
- u"value=\"%s\"/> <input type='button' id='id_refresh_%s' "\
+ tpl += u"<div><textarea id='id_%s' name='id_%s' "\
+ u">%s</textarea> <input type='button' id='id_refresh_%s' "\
u"value='%s' class='input-osm'/>" % (name, name, value, name,
_(u"Refresh"))
return mark_safe(tpl)
@@ -628,7 +818,7 @@ class ImportFiltrWidget(AreaWidget):
"""
Return the appropriate values
"""
- return data.get('id_'+name, None)
+ return data.get('id_' + name, None)
def get_bounding_box_from_value(self, value):
'''
@@ -640,17 +830,18 @@ class ImportFiltrWidget(AreaWidget):
self.xapi_type, self.xapi_tag, self.bounding_box = None, '', None
if not value:
return upper_left_lat, upper_left_lon, lower_right_lat, \
- lower_right_lon
+ lower_right_lon
xapi_m = RE_XAPI.match(value)
if not xapi_m:
return upper_left_lat, upper_left_lon, lower_right_lat, \
- lower_right_lon
+ lower_right_lon
# as the regexp pass, we could be pretty confident
self.xapi_type, self.xapi_tag, self.bounding_box = xapi_m.groups()
upper_left_lon, lower_right_lat, lower_right_lon, upper_left_lat = \
- self.bounding_box.split(',')
+ self.bounding_box.split(',')
return float(upper_left_lat), float(upper_left_lon), \
- float(lower_right_lat), float(lower_right_lon)
+ float(lower_right_lat), float(lower_right_lon)
+
class AreaField(forms.MultiValueField):
'''
@@ -663,33 +854,36 @@ class AreaField(forms.MultiValueField):
return None
return data_list
+
class MultiSelectWidget(forms.SelectMultiple):
class Media:
css = {'all': list(settings.JQUERY_CSS_URLS) + [
settings.STATIC_URL + 'bsmSelect/css/jquery.bsmselect.css',
settings.STATIC_URL + 'bsmSelect/css/jquery.bsmselect.custom.css',
- ]
+ ]
}
js = list(settings.JQUERY_JS_URLS) + [
settings.STATIC_URL + 'bsmSelect/js/jquery.bsmselect.js',
- settings.STATIC_URL + 'bsmSelect/js/jquery.bsmselect.compatibility.js',
- ]
+ settings.STATIC_URL +
+ 'bsmSelect/js/jquery.bsmselect.compatibility.js',
+ ]
def render(self, name, value, attrs=None):
rendered = super(MultiSelectWidget, self).render(name, value, attrs)
rendered += u"<hr class='spacer'/><script type='text/javascript'>\n"\
- u"$.bsmSelect.conf['title'] = \"%(title)s\";\n"\
- u"$(\"#id_%(name)s\").bsmSelect({\n"\
- u" removeLabel: '<strong>X</strong>',\n"\
- u" containerClass: 'bsmContainer',\n"\
- u" listClass: 'bsmList-custom',\n"\
- u" listItemClass: 'bsmListItem-custom',\n"\
- u" listItemLabelClass: 'bsmListItemLabel-custom',\n"\
- u" removeClass: 'bsmListItemRemove-custom'\n"\
- u"});\n"\
- u"</script>\n" % {'name':name, 'title':_("Select...")}
+ u"$.bsmSelect.conf['title'] = \"%(title)s\";\n"\
+ u"$(\"#id_%(name)s\").bsmSelect({\n"\
+ u" removeLabel: '<strong>X</strong>',\n"\
+ u" containerClass: 'bsmContainer',\n"\
+ u" listClass: 'bsmList-custom',\n"\
+ u" listItemClass: 'bsmListItem-custom',\n"\
+ u" listItemLabelClass: 'bsmListItemLabel-custom',\n"\
+ u" removeClass: 'bsmListItemRemove-custom'\n"\
+ u"});\n"\
+ u"</script>\n" % {'name': name, 'title': _("Select...")}
return mark_safe(rendered)
+
class SelectMultipleField(models.ManyToManyField):
'''
Set the widget for the category field
@@ -704,3 +898,4 @@ from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^chimere\.widgets\.PointField"])
add_introspection_rules([], ["^chimere\.widgets\.SelectMultipleField"])
add_introspection_rules([], ["^chimere\.widgets\.RouteField"])
+add_introspection_rules([], ["^chimere\.widgets\.PolygonField"])