summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chimere/admin.py11
-rw-r--r--chimere/forms.py60
-rw-r--r--chimere/locale/fr/LC_MESSAGES/django.po407
-rw-r--r--chimere/migrations/0029_auto__add_propertymodelchoice.py232
-rw-r--r--chimere/models.py67
-rw-r--r--chimere/route.py110
-rw-r--r--chimere/static/chimere/css/styles.css149
-rw-r--r--chimere/static/chimere/img/feed.pngbin0 -> 1453 bytes
-rw-r--r--chimere/static/chimere/img/flag-finish.pngbin0 -> 1652 bytes
-rw-r--r--chimere/static/chimere/img/flag-start.pngbin0 -> 1165 bytes
-rw-r--r--chimere/static/chimere/img/flag-step.pngbin0 -> 1256 bytes
-rw-r--r--chimere/static/chimere/img/images_licences14
-rw-r--r--chimere/static/chimere/js/jquery.chimere.js332
-rw-r--r--chimere/static/chimere/js/nominatim-widget.js42
-rw-r--r--chimere/templates/base.html36
-rw-r--r--chimere/templates/chimere/blocks/categories.html56
-rw-r--r--chimere/templates/chimere/blocks/head_form.html2
-rw-r--r--chimere/templates/chimere/blocks/map_menu.html14
-rw-r--r--chimere/templates/chimere/blocks/map_params.html1
-rw-r--r--chimere/templates/chimere/blocks/multimedia_file.html2
-rw-r--r--chimere/templates/chimere/blocks/routing.html64
-rw-r--r--chimere/templates/chimere/detail.html3
-rw-r--r--chimere/templates/chimere/main_map.html2
-rw-r--r--chimere/templatetags/chimere_tags.py23
-rw-r--r--chimere/urls.py11
-rw-r--r--chimere/views.py37
-rw-r--r--chimere/widgets.py75
-rw-r--r--example_project/locale/fr/LC_MESSAGES/django.po47
-rw-r--r--example_project/settings.py28
29 files changed, 1543 insertions, 282 deletions
diff --git a/chimere/admin.py b/chimere/admin.py
index 97403f0..a063efe 100644
--- a/chimere/admin.py
+++ b/chimere/admin.py
@@ -38,7 +38,8 @@ from chimere.forms import MarkerAdminForm, RouteAdminForm, AreaAdminForm,\
NewsAdminForm, CategoryAdminForm, ImporterAdminForm
from chimere.models import Category, Icon, SubCategory, Marker, \
PropertyModel, News, Route, Area, ColorTheme, Color, RouteFile,\
- MultimediaType, MultimediaFile, PictureFile, Importer, Layer, AreaLayers
+ MultimediaType, MultimediaFile, PictureFile, Importer, Layer, AreaLayers,\
+ PropertyModelChoice
from chimere.utils import unicode_normalize, ShapefileManager, KMLManager
from chimere.widgets import TextareaWidget
@@ -240,6 +241,12 @@ class PictureFileAdmin(admin.ModelAdmin):
list_display = ('name', 'picture', 'miniature', 'order')
list_filter = ('miniature',)
+class PropertyModelChoiceInline(admin.TabularInline):
+ model = PropertyModelChoice
+ extra = 1
+class PropertyModelAdmin(admin.ModelAdmin):
+ inlines = [PropertyModelChoiceInline]
+
# register of differents database fields
admin.site.register(News, NewsAdmin)
admin.site.register(Category, CategoryAdmin)
@@ -248,7 +255,7 @@ admin.site.register(SubCategory, SubCategoryAdmin)
admin.site.register(Marker, MarkerAdmin)
admin.site.register(RouteFile, RouteFileAdmin)
admin.site.register(Route, RouteAdmin)
-admin.site.register(PropertyModel)
+admin.site.register(PropertyModel, PropertyModelAdmin)
admin.site.register(Area, AreaAdmin)
admin.site.register(ColorTheme, ColorThemeAdmin)
admin.site.register(MultimediaType, MultimediaTypeAdmin)
diff --git a/chimere/forms.py b/chimere/forms.py
index 119047d..818fa6e 100644
--- a/chimere/forms.py
+++ b/chimere/forms.py
@@ -33,9 +33,9 @@ from django.core.mail import EmailMessage, BadHeaderError
from chimere.models import Marker, Route, PropertyModel, Property, Area,\
News, Category, SubCategory, RouteFile, MultimediaFile, MultimediaType, \
- PictureFile, Importer
+ PictureFile, Importer, PropertyModelChoice
from chimere.widgets import AreaField, PointField, TextareaWidget, \
- DatePickerWidget
+ DatePickerWidget, ButtonSelectWidget, NominatimWidget
from datetime import timedelta, datetime, tzinfo
@@ -53,13 +53,18 @@ class UTC(tzinfo):
def dst(self, dt):
return ZERO
+def getStaffEmails():
+ return [u.email for u in
+ User.objects.filter(is_staff=True).exclude(email="").order_by('id')]
+
def notifyStaff(subject, body, sender=None):
if not settings.EMAIL_HOST:
return
+ user_list = getStaffEmails()
+ if not user_list:
+ return
if settings.PROJECT_NAME:
subject = u'[%s] %s' % (settings.PROJECT_NAME, subject)
- user_list = [u.email for u in
- User.objects.filter(is_staff=True).exclude(email="").order_by('id')]
headers = {}
if sender:
headers['Reply-To'] = sender
@@ -113,7 +118,7 @@ class CategoryAdminForm(forms.ModelForm):
class Meta:
model = Category
-class MarkerAdminFormBase(forms.ModelForm):
+class MarkerAdminForm(forms.ModelForm):
"""
Main form for marker
"""
@@ -139,12 +144,27 @@ class MarkerAdminFormBase(forms.ModelForm):
keys['initial'] = property_dct
subcategories = keys.pop('subcategories') \
if 'subcategories' in keys else []
- super(MarkerAdminFormBase, self).__init__(*args, **keys)
+ super(MarkerAdminForm, self).__init__(*args, **keys)
if settings.CHIMERE_DAYS_BEFORE_EVENT:
self.fields['start_date'].widget = DatePickerWidget()
self.fields['end_date'].widget = DatePickerWidget()
if subcategories:
self.fields['categories'].choices = subcategories
+ for prop in PropertyModel.objects.filter(available=True):
+ key = "property_%d_%d" % (prop.order, prop.id)
+ if prop.type == 'C':
+ choices = PropertyModelChoice.objects.filter(propertymodel=prop,
+ available=True
+ ).order_by('value')
+ self.fields[key] = forms.ChoiceField(label=prop.name,
+ choices=[('', '--')] + \
+ [(choice.pk, unicode(choice))
+ for choice in choices],
+ required=False)
+ else:
+ self.fields[key] = forms.CharField(label=prop.name,
+ widget=PropertyModel.TYPE_WIDGET[prop.type],
+ required=False)
def clean(self):
'''
@@ -176,7 +196,7 @@ class MarkerAdminFormBase(forms.ModelForm):
"""
Custom save method in order to manage associated properties
"""
- new_marker = super(MarkerAdminFormBase, self).save(*args, **keys)
+ new_marker = super(MarkerAdminForm, self).save(*args, **keys)
if 'status' not in self.cleaned_data:
new_marker.status = 'S'
if new_marker.status == 'A':
@@ -190,16 +210,6 @@ class MarkerAdminFormBase(forms.ModelForm):
new_marker.saveProperties(properties)
return new_marker
-# As we have dynamic fields, it's cleaner to make the class dynamic too
-fields = {}
-# declare properties
-for prop in PropertyModel.objects.filter(available=True):
- key = "property_%d_%d" % (prop.order, prop.id)
- fields[key] = forms.CharField(label=prop.name,
- widget=PropertyModel.TYPE_WIDGET[prop.type],
- required=False)
-MarkerAdminForm = type("MarkerAdminForm", (MarkerAdminFormBase,), fields)
-
class MarkerForm(MarkerAdminForm):
"""
Form for the edit page
@@ -453,3 +463,19 @@ class AreaForm(AreaAdminForm):
class Meta:
model = Area
+class RoutingForm(forms.Form):
+ transport = forms.ChoiceField(label='', widget=ButtonSelectWidget,
+ choices=settings.CHIMERE_ROUTING_TRANSPORT,
+ initial=settings.CHIMERE_ROUTING_TRANSPORT[0][0])
+ start = forms.CharField(label=_(u"Start"), widget=NominatimWidget)
+ end = forms.CharField(label=_(u"Finish"), widget=NominatimWidget)
+ speed = forms.ChoiceField(label=_(u"Speed"), choices=[], required=False)
+
+ def __init__(self, *args, **kwargs):
+ super(RoutingForm, self).__init__(*args, **kwargs)
+ if not settings.CHIMERE_ROUTING_SPEEDS:
+ self.fields.pop('speed')
+ for transport in settings.CHIMERE_ROUTING_SPEEDS:
+ for speed, lbl in settings.CHIMERE_ROUTING_SPEEDS[transport]:
+ self.fields['speed'].widget.choices.append(
+ ("%s_%d" % (transport, speed), lbl))
diff --git a/chimere/locale/fr/LC_MESSAGES/django.po b/chimere/locale/fr/LC_MESSAGES/django.po
index 4462ff1..e61f709 100644
--- a/chimere/locale/fr/LC_MESSAGES/django.po
+++ b/chimere/locale/fr/LC_MESSAGES/django.po
@@ -1,24 +1,23 @@
# Chimère
# Copyright (C) 2008-2012
# This file is distributed under the same license as the Chimère package.
-# Étienne Loks <etienne.loks@peacefrogs.net>, 2008-2011.
+# Étienne Loks <etienne.loks@peacefrogs.net>, 2008-2012.
#
msgid ""
msgstr ""
-"Project-Id-Version: 0.2\n"
+"Project-Id-Version: 2.0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-08-20 21:17+0200\n"
-"PO-Revision-Date: 2010-03-20 20:00+0100\n"
+"POT-Creation-Date: 2012-08-26 17:07+0200\n"
"Last-Translator: Étienne Loks <etienne.loks@peacefrogs.net>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: __init__.py:8 models.py:502
+#: __init__.py:8 models.py:526
msgid "Multimedia files"
msgstr "Fichiers multimedias"
-#: __init__.py:9 models.py:551
+#: __init__.py:9 models.py:583
msgid "Picture files"
msgstr "Fichiers d'image"
@@ -86,382 +85,406 @@ msgstr "Nouveaux points d'intérêt de "
msgid "Last points of interest by area"
msgstr "Nouveaux points d'intérêt par zone"
-#: forms.py:76
+#: forms.py:81
msgid "New submission for"
msgstr "Nouvelle proposition pour"
-#: forms.py:77
+#: forms.py:82
#, python-format
msgid "The new item \"%s\" has been submited in the category: "
msgstr "Le nouvel élément « %s » a été proposé dans la catégorie : "
-#: forms.py:79
+#: forms.py:84
msgid "To valid, precise or unvalid this item: "
msgstr "Pour valider, préciser ou rejeter cet élément : "
-#: forms.py:89
+#: forms.py:94
msgid "Email (optional)"
msgstr "Courriel (optionnel) "
-#: forms.py:90
+#: forms.py:95
msgid "Object"
msgstr "Objet"
-#: forms.py:158
+#: forms.py:163
msgid "End date has been set with no start date"
msgstr "Une date de fin a été donnée sans date de début"
-#: forms.py:171
+#: forms.py:174
msgid "This field is mandatory for the selected categories"
msgstr "Ce champ est obligatoire pour les catégories sélectionnées"
-#: forms.py:385
+#: forms.py:388
msgid "File"
msgstr "Fichier"
-#: forms.py:391
+#: forms.py:394
msgid "Bad file format: this must be a GPX or KML file"
msgstr "Mauvais format de fichier : KML et GPX sont supportés"
-#: forms.py:396 models.py:49 models.py:102 models.py:123 models.py:136
-#: models.py:150 models.py:233 models.py:449 models.py:492 models.py:536
-#: models.py:567 models.py:804 models.py:816 models.py:901
+#: forms.py:399 models.py:50 models.py:103 models.py:124 models.py:137
+#: models.py:151 models.py:234 models.py:473 models.py:516 models.py:560
+#: models.py:643 models.py:881 models.py:893 models.py:978
#: templates/chimere/edit.html:39 templates/chimere/edit_route.html:36
msgid "Name"
msgstr "Nom"
-#: forms.py:405 models.py:853
+#: forms.py:408 models.py:930
msgid "Area"
msgstr "Zone"
-#: models.py:50 models.py:124 models.py:151 models.py:244 models.py:453
-#: models.py:822 models.py:903
+#: forms.py:464
+msgid "Start"
+msgstr "Départ"
+
+#: forms.py:465
+msgid "Finish"
+msgstr "Arrivée :"
+
+#: forms.py:466
+msgid "Speed"
+msgstr "Vitesse"
+
+#: models.py:51 models.py:125 models.py:152 models.py:245 models.py:477
+#: models.py:899 models.py:980
msgid "Available"
msgstr "Disponible"
-#: models.py:51 models.py:912
+#: models.py:52 models.py:989
msgid "Date"
msgstr "Date"
-#: models.py:57 models.py:58
+#: models.py:58 models.py:59
msgid "News"
msgstr "Nouvelle"
-#: models.py:63
+#: models.py:64
msgid "Parameters"
msgstr "Paramètres"
-#: models.py:67
+#: models.py:68
msgid "TinyUrl"
msgstr "Mini-url"
-#: models.py:106 models.py:113 models.py:153
+#: models.py:107 models.py:114 models.py:154
msgid "Color theme"
msgstr "Thème de couleur"
-#: models.py:111
+#: models.py:112
msgid "Code"
msgstr "Code"
-#: models.py:112 models.py:125 models.py:155 models.py:494 models.py:543
-#: models.py:821 models.py:890 models.py:902
+#: models.py:113 models.py:126 models.py:156 models.py:518 models.py:575
+#: models.py:898 models.py:967 models.py:979
msgid "Order"
msgstr "Ordre"
-#: models.py:118
+#: models.py:119
msgid "Color"
msgstr "Couleur"
-#: models.py:131 models.py:149 templates/chimere/main_map.html:13
+#: models.py:132 models.py:150 templates/chimere/main_map.html:13
msgid "Category"
msgstr "Catégorie"
-#: models.py:137 models.py:445 models.py:537 models.py:632
+#: models.py:138 models.py:469 models.py:561 models.py:708
msgid "Image"
msgstr "Image"
-#: models.py:139 models.py:539 models.py:634
+#: models.py:140 models.py:563 models.py:710
msgid "Height"
msgstr "Hauteur"
-#: models.py:140 models.py:540 models.py:635
+#: models.py:141 models.py:564 models.py:711
msgid "Width"
msgstr "Largeur"
-#: models.py:144 models.py:152
+#: models.py:145 models.py:153
msgid "Icon"
msgstr "Icône"
-#: models.py:156
+#: models.py:157
msgid "Marker"
msgstr "Point d'intérêt"
-#: models.py:157 models.py:628 models.py:643
+#: models.py:158 models.py:704 models.py:719
#: templates/chimere/edit_route.html:27
msgid "Route"
msgstr "Trajet"
-#: models.py:158
+#: models.py:159
msgid "Both"
msgstr "Mixte"
-#: models.py:159
+#: models.py:160
msgid "Item type"
msgstr "Type d'élément"
-#: models.py:164
+#: models.py:165
msgid "Sub-category"
msgstr "Sous-catégorie"
-#: models.py:165
+#: models.py:166
msgid "Sub-categories"
msgstr "Sous-catégories"
-#: models.py:211
+#: models.py:212
msgid "Importer type"
msgstr "Type d'import"
-#: models.py:214 models.py:255
+#: models.py:215 models.py:256
msgid "Source"
msgstr "Source"
-#: models.py:216
+#: models.py:217
msgid "Filter"
msgstr "Filtre"
-#: models.py:219
+#: models.py:220
msgid "Associated subcategories"
msgstr "Sous-catégories associées"
-#: models.py:220
+#: models.py:221
msgid "State"
msgstr "État"
-#: models.py:222
+#: models.py:223
msgid "SRID"
msgstr "SRID"
-#: models.py:223
+#: models.py:224
msgid "Zipped file"
msgstr "Fichier zippé"
-#: models.py:226
+#: models.py:227
msgid "Importer"
msgstr "Import"
-#: models.py:235
+#: models.py:236
msgid "Submitter session key"
msgstr "Clé de session du demandeur"
-#: models.py:237
+#: models.py:238
msgid "Submitter name or nickname"
msgstr "Nom ou pseudo du demandeur"
-#: models.py:239
+#: models.py:240
msgid "Submitter email"
msgstr "Courriel du demandeur"
-#: models.py:241
+#: models.py:242
msgid "Submitter comment"
msgstr "Commentaire du demandeur"
-#: models.py:243
+#: models.py:244
msgid "Submited"
msgstr "Soumis"
-#: models.py:245
+#: models.py:246
msgid "Modified"
msgstr "Modifié"
-#: models.py:246
+#: models.py:247
msgid "Disabled"
msgstr "Désactivé"
-#: models.py:247
+#: models.py:248
msgid "Imported"
msgstr "Importé"
-#: models.py:248
+#: models.py:249
msgid "Excluded"
msgstr "Exclu"
-#: models.py:250
+#: models.py:251
msgid "Status"
msgstr "État"
-#: models.py:251
+#: models.py:252
msgid "Import key"
msgstr "Clé d'import"
-#: models.py:253
+#: models.py:254
msgid "Import version"
msgstr "Version de l'import"
-#: models.py:258 templates/chimere/edit.html:56
+#: models.py:259 templates/chimere/edit.html:56
#: templates/chimere/edit_route.html:52
msgid "Start date"
msgstr "Date de début"
-#: models.py:259
+#: models.py:260
msgid "Not mandatory. Set it for dated item such as event. Format YYYY-MM-DD"
msgstr ""
"Optionnel. Précisez ce champ pour les éléments datés comme un événement. "
"Format du champ : AAAA-MM-JJ"
-#: models.py:261 templates/chimere/edit.html:62
+#: models.py:262 templates/chimere/edit.html:62
#: templates/chimere/edit_route.html:58
msgid "End date"
msgstr "Date de fin"
-#: models.py:262
+#: models.py:263
msgid ""
"Not mandatory. Set it only if you have a multi-day event. Format YYYY-MM-DD"
msgstr ""
"Optionnel. Précisez ce champ seulement pour des événements durant plusieurs "
"jours. Format du champ : AAAA-MM-JJ"
-#: models.py:294
+#: models.py:295
msgid "Reference marker"
msgstr "Point d'intérêt de référence"
-#: models.py:295
+#: models.py:296
msgid "Localisation"
msgstr "Localisation"
-#: models.py:297
+#: models.py:298
msgid "Available Date"
msgstr "Date de mise en disponibilité"
-#: models.py:301 templates/chimere/edit.html:49
+#: models.py:302 templates/chimere/edit.html:49
#: templates/chimere/edit_route.html:46
msgid "Description"
msgstr "Description"
-#: models.py:349 models.py:932
+#: models.py:373 models.py:1009
msgid "Point of interest"
msgstr "Point d'intérêt"
-#: models.py:443
+#: models.py:467
msgid "Audio"
msgstr "Audio"
-#: models.py:444
+#: models.py:468
msgid "Video"
msgstr "Vidéo"
-#: models.py:446
+#: models.py:470
msgid "Other"
msgstr "Autre"
-#: models.py:447
+#: models.py:471
msgid "Media type"
msgstr "Type de media"
-#: models.py:450
+#: models.py:474
msgid "Mime type"
msgstr "Type mime"
-#: models.py:452
+#: models.py:476
msgid "Inside an iframe"
msgstr "À l'intérieur d'un iframe"
-#: models.py:456
+#: models.py:480
msgid "Multimedia type"
msgstr "Type de multimedia"
-#: models.py:457
+#: models.py:481
msgid "Multimedia types"
msgstr "Types de multimedia"
-#: models.py:493
+#: models.py:517
msgid "Url"
msgstr "Url"
-#: models.py:496 models.py:541
+#: models.py:520 models.py:565
msgid "Display inside the description?"
msgstr "Apparaît dans la description ?"
-#: models.py:501
+#: models.py:525
msgid "Multimedia file"
msgstr "Fichier multimedia"
-#: models.py:550
+#: models.py:567
+msgid "Thumbnail"
+msgstr "Miniature"
+
+#: models.py:571
+msgid "Thumbnail height"
+msgstr "Hauteur de la miniature"
+
+#: models.py:573
+msgid "Thumbnail width"
+msgstr "Largeur de la miniature"
+
+#: models.py:582
msgid "Picture file"
msgstr "Fichier d'image"
-#: models.py:568
+#: models.py:644
msgid "Raw file (gpx or kml)"
msgstr "Fichier brut (gpx ou kml)"
-#: models.py:569
+#: models.py:645
msgid "Simplified file"
msgstr "Fichier simplifié"
-#: models.py:571
+#: models.py:647
msgid "KML"
msgstr "KML"
-#: models.py:571
+#: models.py:647
msgid "GPX"
msgstr "GPX"
-#: models.py:576
+#: models.py:652
msgid "Route file"
msgstr "Fichier de trajet"
-#: models.py:577
+#: models.py:653
msgid "Route files"
msgstr "Fichiers de trajet"
-#: models.py:627
+#: models.py:703
msgid "Reference route"
msgstr "Trajet de référence"
-#: models.py:631
+#: models.py:707
msgid "Associated file"
msgstr "Fichier associé"
-#: models.py:805
+#: models.py:882
msgid "Layer code"
msgstr "Code pour la couche"
-#: models.py:811
+#: models.py:888
msgid "Layer"
msgstr "Couche"
-#: models.py:817
+#: models.py:894
msgid "Area urn"
msgstr "Urn de la zone"
-#: models.py:819 templates/chimere/blocks/welcome.html:3
+#: models.py:896 templates/chimere/blocks/welcome.html:3
msgid "Welcome message"
msgstr "Message d'accueil"
-#: models.py:823
+#: models.py:900
msgid "Upper left corner"
msgstr "Coin en haut à gauche"
-#: models.py:825
+#: models.py:902
msgid "Lower right corner"
msgstr "Coin en bas à droite"
-#: models.py:827
+#: models.py:904
msgid "Default area"
msgstr "Zone par défaut"
-#: models.py:828
+#: models.py:905
msgid "Only one area is set by default"
msgstr "Seule une zone est définie par défaut"
-#: models.py:832
+#: models.py:909
msgid "Sub-categories checked by default"
msgstr "Sous-catégories cochées par défaut"
-#: models.py:834
+#: models.py:911
msgid "Sub-categories dynamicaly displayed"
msgstr "Sous-categories affichées dynamiquement"
-#: models.py:835
+#: models.py:912
msgid ""
"If checked, categories are only displayed in the menu if they are available "
"on the current extent."
@@ -469,68 +492,68 @@ msgstr ""
"Si coché, les catégories sont disponibles sur le menu seulement si elles "
"apparaissent sur la zone affichée."
-#: models.py:839 models.py:906
+#: models.py:916 models.py:983
msgid "Restricted to theses sub-categories"
msgstr "Restreindre à ces sous-categories"
-#: models.py:840
+#: models.py:917
msgid "If no sub-category is set all sub-categories are available"
msgstr ""
"Si aucune sous-catégorie n'est définie toutes les sous-catégories sont "
"disponibles"
-#: models.py:842
+#: models.py:919
msgid "Link to an external CSS"
msgstr "Lien vers une feuille de style externe"
-#: models.py:844
+#: models.py:921
msgid "Restrict to the area extent"
msgstr "Restreindre à l'étendue de la zone"
-#: models.py:891
+#: models.py:968
msgid "Default layer"
msgstr "Couche par défaut"
-#: models.py:895 models.py:896
+#: models.py:972 models.py:973
msgid "Layers"
msgstr "Couches"
-#: models.py:904
+#: models.py:981
msgid "Mandatory"
msgstr "Obligatoire"
-#: models.py:907
+#: models.py:984
msgid ""
"If no sub-category is set all the property applies to all sub-categories"
msgstr ""
"Si aucune sous-catégorie n'est précisée, cette propriété est disponible pour "
"toutes les sous-catégories"
-#: models.py:909
+#: models.py:986
msgid "Text"
msgstr "Texte"
-#: models.py:910
+#: models.py:987
msgid "Long text"
msgstr "Texte long"
-#: models.py:911
+#: models.py:988
msgid "Password"
msgstr "Mot de passe"
-#: models.py:917
+#: models.py:994
msgid "Type"
msgstr "Type"
-#: models.py:922 models.py:934
+#: models.py:999 models.py:1011
msgid "Property model"
msgstr "Modèle de propriété"
-#: models.py:935
+#: models.py:1012
msgid "Value"
msgstr "Valeur"
-#: models.py:939
+#: models.py:1016
msgid "Property"
msgstr "Propriété"
@@ -630,19 +653,19 @@ msgstr ""
msgid "Bad param"
msgstr "Mauvais paramètre"
-#: views.py:229
+#: views.py:237
msgid "There are missing field(s) and/or errors in the submited form."
msgstr "Il y a des champs manquants ou des erreurs dans ce formulaire."
-#: views.py:312
+#: views.py:319
msgid "Bad file. Please check it with an external software."
msgstr "Fichier incohérent. Merci de le vérifier avec un logiciel externe."
-#: views.py:434
+#: views.py:441
msgid "Comments/request on the map"
msgstr "Commentaires/requètes sur la carte"
-#: views.py:437
+#: views.py:444
msgid ""
"Thank you for your contribution. It will be taken into account. If you have "
"left your email you may be contacted soon for more details."
@@ -651,48 +674,52 @@ msgstr ""
"laissé votre courriel vous serez peut-être contacté bientôt pour plus de "
"détails."
-#: views.py:441
+#: views.py:448
msgid "Temporary error. Renew your message later."
msgstr "Erreur temporaire. Réenvoyez votre message plus tard."
-#: views.py:572
+#: views.py:584
msgid "No category available in this area."
msgstr "Pas de catégorie disponible sur cette zone."
-#: views.py:679
+#: views.py:716
msgid "Incorrect choice in the list"
msgstr "Choix incorrect dans la liste"
-#: widgets.py:187
+#: widgets.py:180
+msgid "Street, City, Country"
+msgstr "Rue, Commune, Pays"
+
+#: widgets.py:246
msgid "Latitude"
msgstr "Latitude"
-#: widgets.py:187
+#: widgets.py:246
msgid "Longitude"
msgstr "Longitude"
-#: widgets.py:212
+#: widgets.py:271
msgid "Invalid point"
msgstr "Point invalide"
-#: widgets.py:262
+#: widgets.py:321
msgid "Creation mode"
msgstr "Mode création"
-#: widgets.py:263
+#: widgets.py:322
msgid "To start drawing the route click on the toggle button: \"Draw\"."
msgstr ""
"Pour commencer le dessin cliquez sur le bouton&nbsp;: «&nbsp;Tracer&nbsp;»."
-#: widgets.py:265
+#: widgets.py:324
msgid "Then click on the map to begin the drawing."
msgstr "Puis cliquez sur la carte pour commencer le dessin."
-#: widgets.py:266
+#: widgets.py:325
msgid "You can add points by clicking again."
msgstr "Vous pouvez ajouter des points en cliquant de nouveau."
-#: widgets.py:267
+#: widgets.py:326
msgid ""
"To finish the drawing double click. When the drawing is finished you can "
"edit it."
@@ -700,7 +727,7 @@ msgstr ""
"Pour finir le tracé double-cliquez. Quand le tracé est fini vous pouvez "
"toujours l'éditer."
-#: widgets.py:269
+#: widgets.py:328
msgid ""
"While creating to undo a drawing click again on the toggle button \"Stop "
"drawing\"."
@@ -708,17 +735,17 @@ msgstr ""
"En mode création vous pouvez annuler un tracé en appuyant sur le bouton "
"«&nbsp;Arrêter le tracé&nbsp;»."
-#: widgets.py:274
+#: widgets.py:333
msgid "Modification mode"
msgstr "Mode modification"
-#: widgets.py:275
+#: widgets.py:334
msgid "To move a point click on it and drag it to the desired position."
msgstr ""
"Pour bouger un point, cliquez dessus, maintenez le click pour le déposer à "
"la position désirée."
-#: widgets.py:276
+#: widgets.py:335
msgid ""
"To delete a point move the mouse cursor over it and press the \"d\" or \"Del"
"\" key."
@@ -726,7 +753,7 @@ msgstr ""
"Pour supprimer un point, mettez le curseur de la souris sur celui-ci et "
"appuyez sur le touche «&nbsp;d&nbsp;» ou «&nbsp;Suppr&nbsp;»."
-#: widgets.py:278
+#: widgets.py:337
msgid ""
"To add a point click in the middle of a segment and drag the new point to "
"the desired position"
@@ -735,33 +762,33 @@ msgstr ""
"maintenez le bouton appuyé et déplacez le nouveau point à la position "
"désirée."
-#: widgets.py:285
+#: widgets.py:344
msgid "Give a name and set category before uploading a file."
msgstr ""
"Renseignez le nom et choisissez au moins une catégorie avant de déposer un "
"fichier."
-#: widgets.py:288
+#: widgets.py:347
msgid "Upload a route file (GPX or KML)"
msgstr "Déposer un trajet (fichier GPX ou KML)"
-#: widgets.py:289
+#: widgets.py:348
msgid "or"
msgstr "ou"
-#: widgets.py:294
+#: widgets.py:353
msgid "Start \"hand\" drawing"
msgstr "Commencer le tracé manuellement"
-#: widgets.py:317
+#: widgets.py:376
msgid "Move on the map"
msgstr "Se déplacer"
-#: widgets.py:317
+#: widgets.py:376
msgid "Draw"
msgstr "Tracer"
-#: widgets.py:442
+#: widgets.py:501
msgid "Select..."
msgstr "Sélectionner..."
@@ -809,6 +836,10 @@ msgstr "Partager sur"
msgid "Share"
msgstr "Partager"
+#: templates/chimere/detail.html:36
+msgid "Propose a modification"
+msgstr "Proposer une modification"
+
#: templates/chimere/edit.html:20
msgid "Error"
msgstr "Erreur"
@@ -858,7 +889,11 @@ msgstr "Votre courriel"
msgid "Comments about your submission"
msgstr "Commentaires au sujet de votre proposition"
-#: templates/chimere/edit.html:133 templates/chimere/edit_route.html:77
+#: templates/chimere/edit.html:134
+msgid "Upload in progress. Please wait..."
+msgstr "Traitement en cours. Veuillez patienter..."
+
+#: templates/chimere/edit.html:151 templates/chimere/edit_route.html:77
msgid "Propose"
msgstr "Proposez"
@@ -913,7 +948,39 @@ msgstr "Ce site utilise Chimère"
msgid "Map"
msgstr "Carte"
-#: templates/chimere/blocks/map_params.html:6
+#: templates/chimere/blocks/map_menu.html:5
+msgctxt "routing"
+msgid "From"
+msgstr "En partir"
+
+#: templates/chimere/blocks/map_menu.html:6
+msgctxt "routing"
+msgid "Add a step"
+msgstr "Ajout d'une étape"
+
+#: templates/chimere/blocks/map_menu.html:7
+msgctxt "routing"
+msgid "To"
+msgstr "Y aller"
+
+#: templates/chimere/blocks/map_menu.html:8
+msgctxt "routing"
+msgid "Clear the itinerary"
+msgstr "Effacer l'itinéraire"
+
+#: templates/chimere/blocks/map_menu.html:10
+msgid "Zoom in"
+msgstr "Zoomer en avant"
+
+#: templates/chimere/blocks/map_menu.html:11
+msgid "Zoom out"
+msgstr "Zoomer en arrière"
+
+#: templates/chimere/blocks/map_menu.html:12
+msgid "Center the map here"
+msgstr "Centrer la carte ici"
+
+#: templates/chimere/blocks/map_params.html:8
msgid "Permalink"
msgstr "Lien permanent"
@@ -923,6 +990,31 @@ msgstr ""
"Utilisez un navigateur internet plus récent ou installez le greffon non "
"libre Flash."
+#: templates/chimere/blocks/routing.html:4
+#: templates/chimere/blocks/routing.html:44
+msgid "Itinerary"
+msgstr "Itinéraire"
+
+#: templates/chimere/blocks/routing.html:14
+msgid "Search"
+msgstr "Rechercher"
+
+#: templates/chimere/blocks/routing.html:20
+msgid "Modify"
+msgstr "Modifier"
+
+#: templates/chimere/blocks/routing.html:23
+msgid "New search"
+msgstr "Nouvelle recherche"
+
+#: templates/chimere/blocks/routing.html:31
+msgid "Start:"
+msgstr "Départ :"
+
+#: templates/chimere/blocks/routing.html:35
+msgid "Finish:"
+msgstr "Arrivée :"
+
#: templates/chimere/blocks/submited.html:3
msgid ""
"Your new proposition/modification has been submited. A moderator will treat "
@@ -987,26 +1079,5 @@ msgstr "Choisir une zone pré-définie"
msgid "Or select the area by zooming and panning this map"
msgstr "Ou sélectionner une zone en zoomant et en se déplaçant sur cette carte"
-#~ msgid "Submit a modification"
-#~ msgstr "Proposer une modification"
-
-#~ msgid "Add/modify a site"
-#~ msgstr "Ajouter ou modifier un site"
-
-#~ msgid "Categorys"
-#~ msgstr "Catégories"
-
-#~ msgid "Theme"
-#~ msgstr "Thème"
-
-#~ msgid "Subtheme"
-#~ msgstr "Sous-thème"
-
-#~ msgid "Subthemes"
-#~ msgstr "Sous-thèmes"
-
-#~ msgid "Themes"
-#~ msgstr "Thèmes"
-
-#~ msgid "Site name"
-#~ msgstr "Nom du site"
+#~ msgid "End"
+#~ msgstr "Fin"
diff --git a/chimere/migrations/0029_auto__add_propertymodelchoice.py b/chimere/migrations/0029_auto__add_propertymodelchoice.py
new file mode 100644
index 0000000..b80129f
--- /dev/null
+++ b/chimere/migrations/0029_auto__add_propertymodelchoice.py
@@ -0,0 +1,232 @@
+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+ def forwards(self, orm):
+ # Adding model 'PropertyModelChoice'
+ db.create_table('chimere_propertymodelchoice', (
+ ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
+ ('propertymodel', self.gf('django.db.models.fields.related.ForeignKey')(related_name='choices', to=orm['chimere.PropertyModel'])),
+ ('value', self.gf('django.db.models.fields.CharField')(max_length=150)),
+ ('available', self.gf('django.db.models.fields.BooleanField')(default=True)),
+ ))
+ db.send_create_signal('chimere', ['PropertyModelChoice'])
+
+
+ def backwards(self, orm):
+ # Deleting model 'PropertyModelChoice'
+ db.delete_table('chimere_propertymodelchoice')
+
+
+ models = {
+ 'chimere.area': {
+ 'Meta': {'ordering': "('order', 'name')", 'object_name': 'Area'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'default_subcategories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False', 'blank': 'True'}),
+ 'dynamic_categories': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'external_css': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layers': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'through': "orm['chimere.AreaLayers']", 'to': "orm['chimere.Layer']"}),
+ 'lower_right_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'restrict_to_extent': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'areas'", 'blank': 'True', 'db_table': "'chimere_subcategory_areas'", 'to': "orm['chimere.SubCategory']"}),
+ 'upper_left_corner': ('django.contrib.gis.db.models.fields.PointField', [], {'default': "'POINT(0 0)'"}),
+ 'urn': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '50', 'blank': 'True'}),
+ 'welcome_message': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.arealayers': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'AreaLayers'},
+ 'area': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Area']"}),
+ 'default': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Layer']"}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.category': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Category'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.color': {
+ 'Meta': {'ordering': "['order']", 'object_name': 'Color'},
+ 'code': ('django.db.models.fields.CharField', [], {'max_length': '6'}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.colortheme': {
+ 'Meta': {'object_name': 'ColorTheme'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.icon': {
+ 'Meta': {'object_name': 'Icon'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.importer': {
+ 'Meta': {'object_name': 'Importer'},
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'filtr': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'importer_type': ('django.db.models.fields.CharField', [], {'max_length': '4'}),
+ 'source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'srid': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'state': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'zipped': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
+ },
+ 'chimere.layer': {
+ 'Meta': {'object_name': 'Layer'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'layer_code': ('django.db.models.fields.TextField', [], {'max_length': '300'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.marker': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Marker'},
+ 'available_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'point': ('chimere.widgets.PointField', [], {}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_marker'", 'null': 'True', 'to': "orm['chimere.Marker']"}),
+ 'route': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'associated_marker'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.multimediafile': {
+ 'Meta': {'object_name': 'MultimediaFile'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'multimedia_files'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'multimedia_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.MultimediaType']"}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'url': ('django.db.models.fields.URLField', [], {'max_length': '200'})
+ },
+ 'chimere.multimediatype': {
+ 'Meta': {'object_name': 'MultimediaType'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'iframe': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'media_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'mime_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.news': {
+ 'Meta': {'object_name': 'News'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'content': ('django.db.models.fields.TextField', [], {}),
+ 'date': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.picturefile': {
+ 'Meta': {'object_name': 'PictureFile'},
+ 'height': ('django.db.models.fields.IntegerField', [], {}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'pictures'", 'to': "orm['chimere.Marker']"}),
+ 'miniature': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {'default': '1'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}),
+ 'thumbnailfile': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'thumbnailfile_width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.property': {
+ 'Meta': {'object_name': 'Property'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'marker': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Marker']"}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.TextField', [], {})
+ },
+ 'chimere.propertymodel': {
+ 'Meta': {'ordering': "('order',)", 'object_name': 'PropertyModel'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'mandatory': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {}),
+ 'subcategories': ('chimere.widgets.SelectMultipleField', [], {'symmetrical': 'False', 'related_name': "'properties'", 'blank': 'True', 'to': "orm['chimere.SubCategory']"}),
+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '1'})
+ },
+ 'chimere.propertymodelchoice': {
+ 'Meta': {'object_name': 'PropertyModelChoice'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'propertymodel': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'choices'", 'to': "orm['chimere.PropertyModel']"}),
+ 'value': ('django.db.models.fields.CharField', [], {'max_length': '150'})
+ },
+ 'chimere.route': {
+ 'Meta': {'ordering': "('status', 'name')", 'object_name': 'Route'},
+ 'associated_file': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.RouteFile']", 'null': 'True', 'blank': 'True'}),
+ 'categories': ('chimere.widgets.SelectMultipleField', [], {'to': "orm['chimere.SubCategory']", 'symmetrical': 'False'}),
+ 'end_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'height': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'import_key': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_source': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'import_version': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'picture': ('django.db.models.fields.files.ImageField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+ 'ref_item': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'submited_route'", 'null': 'True', 'to': "orm['chimere.Route']"}),
+ 'route': ('chimere.widgets.RouteField', [], {}),
+ 'start_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'blank': 'True'}),
+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'submiter_comment': ('django.db.models.fields.TextField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+ 'submiter_email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
+ 'submiter_name': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'submiter_session_key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'null': 'True', 'blank': 'True'}),
+ 'width': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.routefile': {
+ 'Meta': {'ordering': "('name',)", 'object_name': 'RouteFile'},
+ 'file_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'raw_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
+ 'simplified_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'})
+ },
+ 'chimere.subcategory': {
+ 'Meta': {'ordering': "['category', 'order']", 'object_name': 'SubCategory'},
+ 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+ 'category': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Category']"}),
+ 'color_theme': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.ColorTheme']", 'null': 'True', 'blank': 'True'}),
+ 'icon': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['chimere.Icon']"}),
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'item_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
+ 'order': ('django.db.models.fields.IntegerField', [], {})
+ },
+ 'chimere.tinyurl': {
+ 'Meta': {'object_name': 'TinyUrl'},
+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+ 'parameters': ('django.db.models.fields.CharField', [], {'max_length': '500'})
+ }
+ }
+
+ complete_apps = ['chimere'] \ No newline at end of file
diff --git a/chimere/models.py b/chimere/models.py
index 4f6d4e0..8f07576 100644
--- a/chimere/models.py
+++ b/chimere/models.py
@@ -25,6 +25,7 @@ import simplejson as json
from lxml import etree
from PIL import Image
from subprocess import Popen, PIPE
+from BeautifulSoup import BeautifulSoup
from django.conf import settings
from django.contrib.gis.db import models
@@ -194,6 +195,14 @@ class SubCategory(models.Model):
return [(category, sub_cats) for category, sub_cats \
in sub_categories.items()]
+ @classmethod
+ def getAvailableTuples(cls, area_name=None):
+ cats = []
+ for cat, subcats in cls.getAvailable(area_name=area_name):
+ cats.append((unicode(cat),
+ [(subcat.pk, subcat.name) for subcat in subcats]))
+ return cats
+
IMPORTERS = {'KML':KMLManager,
'OSM':OSMManager,
'SHP':ShapefileManager
@@ -344,6 +353,29 @@ class Marker(GeographicItem):
if settings.CHIMERE_DAYS_BEFORE_EVENT:
return self.start_date
+ @property
+ def description_short(self):
+ if not self.description:
+ return ''
+ if len(self.description) <= settings.CHIMERE_SHORT_DESC_LENGTH:
+ return self.description
+ desc = self.description[:settings.CHIMERE_SHORT_DESC_LENGTH]
+ short_desc = ""
+ # find a correct opportunity to cut
+ for idx, c in enumerate(reversed(desc)):
+ if c == '>':
+ break
+ if c == '<':
+ short_desc = desc[:-(idx+1)]
+ break
+ if not short_desc:
+ for idx, c in enumerate(reversed(desc)):
+ if c == ' ' or c == '\n':
+ short_desc = desc[:-(idx+1)]
+ break
+ short_desc += "..."
+ return BeautifulSoup(short_desc).prettify()
+
class Meta:
ordering = ('status', 'name')
verbose_name = _(u"Point of interest")
@@ -962,11 +994,15 @@ class PropertyModel(models.Model):
TYPE = (('T', _('Text')),
('L', _('Long text')),
('P', _('Password')),
- ('D', _("Date")))
+ ('D', _("Date")),
+ ('C', _("Choices")),
+ )
TYPE_WIDGET = {'T':forms.TextInput,
'L':TextareaWidget,
'P':forms.PasswordInput,
- 'D':DatePickerWidget}
+ 'D':DatePickerWidget,
+ 'C':forms.Select
+ }
type = models.CharField(_(u"Type"), max_length=1, choices=TYPE)
def __unicode__(self):
return self.name
@@ -979,6 +1015,19 @@ class PropertyModel(models.Model):
'''
return 'property_%d_%d' % (self.order, self.id)
+class PropertyModelChoice(models.Model):
+ '''Choices for property model
+ '''
+ propertymodel = models.ForeignKey(PropertyModel, related_name='choices',
+ verbose_name=_(u"Property model"))
+ value = models.CharField(_(u"Value"), max_length=150)
+ available = models.BooleanField(_(u"Available"), default=True)
+ def __unicode__(self):
+ return unicode(self.value)
+
+ class Meta:
+ verbose_name = _(u"Model property choice")
+
class Property(models.Model):
'''Property for a POI
'''
@@ -987,7 +1036,14 @@ class Property(models.Model):
verbose_name=_(u"Property model"))
value = models.TextField(_(u"Value"))
def __unicode__(self):
- return "%s : %s" % (str(self.propertymodel), self.value)
+ if self.propertymodel.type == 'C':
+ try:
+ return unicode(PropertyModelChoice.objects.get(
+ pk=self.value).value)
+ except self.DoesNotExist:
+ return ""
+ return unicode(self.value)
+
class Meta:
verbose_name = _(u"Property")
@@ -998,6 +1054,11 @@ class Property(models.Model):
return datetime.date(*[int(val) for val in self.value.split('-')])
except:
return ""
+ if self.propertymodel.type == 'C':
+ try:
+ return PropertyModelChoice.objects.get(pk=self.value)
+ except self.DoesNotExist:
+ return None
else:
return self.value
diff --git a/chimere/route.py b/chimere/route.py
new file mode 100644
index 0000000..9c8b59c
--- /dev/null
+++ b/chimere/route.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (C) 2012 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
+#
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# See the file COPYING for details.
+
+"""
+Routing management
+"""
+
+import os, re, shutil, tempfile
+from BeautifulSoup import BeautifulSoup
+from subprocess import Popen, PIPE
+from django.contrib.gis.gdal import DataSource
+
+from django.conf import settings
+
+class Router:
+ def route(self, lon1, lat1, lon2, lat2, transport='foot'):
+ '''
+ Get a list of geojson polylines
+ '''
+ return []
+
+class RoutinoRouter(Router):
+ re_desc = [re.compile("<tr class='n'>"), re.compile("<tr class='s'>"),
+ re.compile("<tr class='t'>")]
+ def route(self, lon1, lat1, lon2, lat2, steps=[], transport='foot'):
+ '''
+ Get a list of geojson polylines and route description
+ '''
+ language = settings.LANGUAGE_CODE.split('-')[0]
+ args = [settings.CHIMERE_ROUTING_ENGINE['PATH'],
+ "--dir=%s" % settings.CHIMERE_ROUTING_ENGINE['DB_PATH'],
+ "--transport=%s" % transport,
+ "--language=%s" % language,
+ "--shortest",
+ "--output-html",
+ "--output-gpx-track",
+ "--lat1=%0.15f" % lat1,
+ "--lon1=%0.15f" % lon1,
+ ]
+ lonlat_index = 1
+ for lon, lat in steps:
+ lonlat_index += 1
+ args += ["--lat%d=%0.15f" % (lonlat_index, lat),
+ "--lon%d=%0.15f" % (lonlat_index, lon)]
+ lonlat_index += 1
+ args += ["--lat%d=%0.15f" % (lonlat_index, lat2),
+ "--lon%d=%0.15f" % (lonlat_index, lon2)]
+ tmp_dir = tempfile.mkdtemp(prefix='chimere_') + os.sep
+ p = Popen(args, stdout=PIPE, cwd=tmp_dir)
+ p.communicate()
+ ds = DataSource(tmp_dir + 'shortest-track.gpx')
+ if not ds:
+ return [], None, None
+ layer = ds[0]
+ trk_layer = None
+ for layer in ds:
+ if layer.name == 'tracks':
+ trk_layer = layer
+ break
+ multilines = trk_layer.get_geoms()
+ res = []
+ for multiline in multilines:
+ res += [geom.geojson for geom in multiline]
+ desc = []
+ # only keeping interessant lines of the desc
+ for line in open(tmp_dir + 'shortest.html').readlines():
+ if [True for r in self.re_desc if r.match(line)]:
+ desc.append(BeautifulSoup(line).prettify())
+ total = self.webify(desc[-1])
+ desc = desc[1:-2]
+ # very fragile piece of code but only break the numerotation
+ number_tpl = '<tr class="n"><span class="number">%d.</span>'
+ desc = [re.sub('<tr class="n">', number_tpl % (idx/2+1), d)
+ if idx % 2 else d
+ for idx, d in enumerate(desc)]
+ desc = self.webify(BeautifulSoup('\n'.join(desc)).prettify())
+ desc = re.sub(" \[", "", desc)
+ desc = re.sub(" \]", "", desc)
+ shutil.rmtree(tmp_dir)
+ return res, desc, total
+
+ @staticmethod
+ def webify(lbl):
+ lbl = re.sub("<td", "<span", lbl)
+ lbl = re.sub("</td>", "</span>", lbl)
+ lbl = re.sub("</tr>", "</div>", lbl)
+ lbl = re.sub("<tr", "<div", lbl)
+ return lbl
+
+router = None
+if settings.CHIMERE_ROUTING_ENGINE['ENGINE'] == 'routino':
+ router = RoutinoRouter()
+
diff --git a/chimere/static/chimere/css/styles.css b/chimere/static/chimere/css/styles.css
index f8ed3fe..023c037 100644
--- a/chimere/static/chimere/css/styles.css
+++ b/chimere/static/chimere/css/styles.css
@@ -15,7 +15,8 @@ a, a:link, a:visited, legend,
h2, h3, th, .action li, .action li a,
.action li li a, #no-js-message,
-#footer a, #footer a:link, #footer a:visited, .ui-widget-header{
+#footer a, #footer a:link, #footer a:visited, .ui-widget-header,
+#chimere_itinerary td.l{
color:#fff;
}
@@ -25,11 +26,22 @@ h2, h3, th, .action li, .action li a,
color:#333;
}
+.nominatim-widget{
+ color:#aaa;
+}
+
+#chimere_total_label td.l{
+ color:#000;
+}
+
/* background-color definition */
body, h2, h3, th,
.ui-widget-header,
-.action li.selected, #no-js-message{
+.action li.selected, #no-js-message,
+#content .olControlLayerSwitcher .layersDiv,
+#content .olControlLayerSwitcher span,
+#chimere_itinerary td.l{
background-color:#449506;
}
@@ -38,10 +50,11 @@ body, h2, h3, th,
}
fieldset, .action li, #content,
-#map-footer, #panel, #areas,
+#map-footer, #panel, #chimere_itinerary_panel, #areas,
#welcome, #detail, .detail_footer a,
#content .olControlLayerSwitcher .layersDiv,
#content .olControlLayerSwitcher span,
+#chimere_total_label td.l,
#main-map, .window{
background-color:#FFF;
}
@@ -63,7 +76,7 @@ div.warning,
#content,
.action li.selected,
#content .olControlLayerSwitcher .layersDiv,
-#panel, #map-footer,
+#panel, #map-footer, #chimere_itinerary_panel,
#utils-div{
border:1px solid #327e04;
}
@@ -79,7 +92,7 @@ div.warning,
opacity:0.9;
}
-#panel, #areas, #detail, #category_detail{
+#panel, #areas, #detail, #category_detail, #chimere_itinerary_panel{
opacity:0.8;
}
@@ -153,7 +166,6 @@ h3{
h4, caption{
font-weight:normal;
- font-style:italic;
margin:0;
text-align:left;
}
@@ -309,23 +321,23 @@ ul#action-2 {
max-width:280px;
}
-ul#share{
+ul.share{
list-style-type:none;
margin:0;
padding:0;
}
-ul#share li{
+ul.share li{
display:inline;
line-height:22px;
vertical-align: bottom;
}
-#share a{
+.share a{
text-decoration:None;
}
-#share img{
+.share img{
border:None;
width:22px;
height:22px;
@@ -355,8 +367,6 @@ ul#share li{
#main-map{
position:absolute;
- margin:0px;
- padding:0px;
height:93%;
margin:0;
padding:0;
@@ -409,12 +419,110 @@ ul#share li{
top:50px;
right:18px;
width:300px;
- bottom:44px;
+ max-height:300px;
overflow:auto;
padding:0.5em;
padding-top:0;
}
+#chimere_itinerary_panel,
+#chimere_itinerary{
+ display:none;
+}
+
+#chimere_itinerary_panel label{
+ color:#000;
+}
+
+#chimere_itinerary_panel p
+{
+ margin:0.5em;
+}
+
+#total_label_div{
+ margin:5px 0;
+}
+
+.itinerary_label{
+ font-size:0.9em;
+ padding-top:0.5em;
+ font-style:italic;
+}
+
+.itinerary_label .label{
+ font-style:normal;
+ font-weight:bold;
+ padding:3px 8px;
+}
+
+
+#chimere_itinerary_content{
+ overflow:auto;
+ height:190px;
+ margin-top:10px;
+}
+
+#chimere_itinerary_content span.l{
+ padding:5px;
+ width:60px;
+}
+
+#chimere_itinerary_content span.j{
+ font-style:italic;
+}
+
+#chimere_itinerary_content .number{
+ font-weight:bold;
+}
+
+#chimere_itinerary_content span.t,
+#chimere_itinerary_content span.b
+{
+ text-transform: lowercase;
+}
+
+#chimere_map_menu{
+ z-index:4;
+ display:none;
+ position:absolute;
+ padding:0.5em;
+ background-color:#fff;
+ border:1px solid #bbb;
+ -webkit-border-radius: 0 8px 8px 8px;
+ -moz-border-radius: 0 8px 8px 8px;
+ border-radius: 0 8px 8px 8px;
+}
+
+#map_menu_clear{
+ display:none;
+}
+
+#map_menu_zoomin{
+ border-top:1px solid #999;
+}
+
+#chimere_map_menu ul, #chimere_map_menu li{
+ padding:0.2em;
+ margin:0;
+ list-style:none;
+}
+
+#chimere_map_menu li:hover{
+ cursor:pointer;
+ background-color:#ccc;
+}
+
+.nominatim-label{
+ display:block;
+ font-size:0.9em;
+ font-weight:bold;
+ height:2.8em;
+}
+
+.nominatim-widget{
+ font-style:italic;
+}
+
.simple #panel{
top:5px;
}
@@ -533,26 +641,18 @@ p.warning{
}
-#welcome_button,
+a#welcome_button,
+a#routing_button,
#permalink{
display: block;
- text-align:center;
margin:0.3em;
padding:0.2em;
-}
-
-a#welcome_button,
-#permalink{
+ width:100%;
font-size:14px;
text-align:center;
text-decoration:none;
}
-#welcome_button,
-#permalink{
- width:100%;
-}
-
/* forms */
table.inline-table{
@@ -595,7 +695,6 @@ table.inline-table td input[type=file]{
margin-right: auto;
}
-
/* openlayer customisation */
.olControlPermalink {
display: block;
diff --git a/chimere/static/chimere/img/feed.png b/chimere/static/chimere/img/feed.png
new file mode 100644
index 0000000..19d2246
--- /dev/null
+++ b/chimere/static/chimere/img/feed.png
Binary files differ
diff --git a/chimere/static/chimere/img/flag-finish.png b/chimere/static/chimere/img/flag-finish.png
new file mode 100644
index 0000000..04bfa1d
--- /dev/null
+++ b/chimere/static/chimere/img/flag-finish.png
Binary files differ
diff --git a/chimere/static/chimere/img/flag-start.png b/chimere/static/chimere/img/flag-start.png
new file mode 100644
index 0000000..c93f2a3
--- /dev/null
+++ b/chimere/static/chimere/img/flag-start.png
Binary files differ
diff --git a/chimere/static/chimere/img/flag-step.png b/chimere/static/chimere/img/flag-step.png
new file mode 100644
index 0000000..5556c94
--- /dev/null
+++ b/chimere/static/chimere/img/flag-step.png
Binary files differ
diff --git a/chimere/static/chimere/img/images_licences b/chimere/static/chimere/img/images_licences
index 0e732fc..cbc9307 100644
--- a/chimere/static/chimere/img/images_licences
+++ b/chimere/static/chimere/img/images_licences
@@ -1,5 +1,5 @@
-* Upload image credit
+* Upload image credit (upload.png)
* Farm-Fresh layer gps.png in Farm-Fresh Web Icons
Author: FatCow Web Hosting
@@ -16,7 +16,7 @@ Author: The Tango! Desktop Project
Licence: Public domain
Url: http://commons.wikimedia.org/wiki/File:Internet-web-browser.svg
-* Drawing image credit
+* Drawing image credit (drawing.png)
* Icons from the Tango! project set.
Author: The Tango! Desktop Project
@@ -24,9 +24,17 @@ Licence: Public domain
Url: http://commons.wikimedia.org/wiki/File:Edit-find-replace.svg
Url 2: http://commons.wikimedia.org/wiki/File:Internet-web-browser.svg
-* Quaver image credit
+* Quaver image credit (8thNote.png)
* An 8th-note.
Author: Sbrools
Licence: Public domain
Url: https://commons.wikimedia.org/wiki/File:8thNote.svg
+
+* Flags image credit (flag-start.png, flag-step.png, flag-finish.png)
+
+Author: FatCow Web Hosting
+Licence: Creative Commons Attribution 3.0 United States license
+Url: https://upload.wikimedia.org/wikipedia/commons/c/cb/Farm-Fresh_flag_1.png
+ https://upload.wikimedia.org/wikipedia/commons/8/81/Farm-Fresh_flag_blue.png
+ https://upload.wikimedia.org/wikipedia/commons/6/64/Farm-Fresh_flag_finish.png
diff --git a/chimere/static/chimere/js/jquery.chimere.js b/chimere/static/chimere/js/jquery.chimere.js
index fbb3ecd..06b4812 100644
--- a/chimere/static/chimere/js/jquery.chimere.js
+++ b/chimere/static/chimere/js/jquery.chimere.js
@@ -74,13 +74,22 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
// Provide this function for overriding the getSubcategories default
get_subcategories_fx: null,
hide_popup_fx: null,
+ // if leave to false every click on the map hide the pop-up
+ explicit_popup_hide: false,
controls:[new OpenLayers.Control.Navigation(),
new OpenLayers.Control.SimplePanZoom(),
new OpenLayers.Control.ScaleLine()],
+ popupClass: OpenLayers.Popup.FramedCloud,
+ popupContentFull: false, // if true the detail is inside the popup
+ category_accordion: true, // category opening behave like an accordion
maxResolution: 156543.0399,
units: 'm',
projection: new OpenLayers.Projection('EPSG:4326'),
- theme:null,
+ theme: null,
+ routing: false, // enable routing management
+ routing_panel_open: function(){
+ $('#chimere_itinerary_panel').dialog('open');
+ },
current_feature: null, // To store the active POI
current_control: null, // To store the current control
current_popup: null, // To store the current POI popup displayed
@@ -119,6 +128,8 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
map_options['restrictedExtent'] = settings.restricted_extent;
}
+ settings.current_position = null;
+
/* Create map object */
settings.map = map = new OpenLayers.Map(map_element, map_options);
@@ -168,6 +179,40 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
}
settings.map.setBaseLayer(
settings.map_layers[settings.selected_map_layer]);
+
+ /* manage the context menu */
+ $('#map_menu_zoomin').bind("click", methods.zoomIn);
+ $('#map_menu_zoomout').bind("click", methods.zoomOut);
+ $('#map_menu_center').bind("click", methods.mapCenter);
+ /* manage the routing */
+ if (settings.routing){
+ settings.routing_start = null;
+ settings.routing_steps = new Array();
+ settings.routing_end = null;
+ settings.icon_start = new OpenLayers.Icon(
+ STATIC_URL + "chimere/img/flag-start.png",
+ new OpenLayers.Size(32, 32),
+ new OpenLayers.Pixel(0, -32));
+ settings.icon_step = new OpenLayers.Icon(
+ STATIC_URL + "chimere/img/flag-step.png",
+ new OpenLayers.Size(32, 32),
+ new OpenLayers.Pixel(0, -32));
+ settings.icon_end = new OpenLayers.Icon(
+ STATIC_URL + "chimere/img/flag-finish.png",
+ new OpenLayers.Size(32, 32),
+ new OpenLayers.Pixel(0, -32));
+ $('#map_menu_from').bind("click", methods.routingFrom);
+ $('#map_menu_step').bind("click", methods.routingAddStep);
+ $('#map_menu_to').bind("click", methods.routingTo);
+ $('#map_menu_clear').bind("click", methods.routingClear);
+ settings.layerRoute = new OpenLayers.Layer.Vector("Route Layer");
+ settings.map.addLayer(settings.layerRoute);
+ settings.layerRoute.setOpacity(0.8);
+ settings.layerRouteMarker = new OpenLayers.Layer.Markers(
+ 'Route markers');
+ settings.map.addLayer(settings.layerRouteMarker);
+ settings.layerRouteMarker.setOpacity(0.8);
+ }
/* Vectors layer */
settings.layerVectors = new OpenLayers.Layer.Vector("Vector Layer");
settings.map.addLayer(settings.layerVectors);
@@ -211,7 +256,7 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
methods.loadGeoObjects();
// Hide popUp when clicking on map
settings.map.events.register('click', settings.map,
- methods.hidePopup);
+ methods.displayMapMenu);
} else {
if (!settings.edition_type_is_route){
map.events.register('click', settings.map,
@@ -225,6 +270,43 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
}
}, // end of init
+ // zoom in from the map menu
+ zoomIn: function(){
+ methods.mapCenter();
+ settings.map.zoomIn();
+ },
+
+ // zoom out from the map menu
+ zoomOut: function(){
+ methods.mapCenter();
+ settings.map.zoomOut();
+ },
+
+ // center from the map menu
+ mapCenter: function(){
+ $('#chimere_map_menu').hide();
+ settings.map.setCenter(settings.current_position);
+ },
+
+ /*
+ * Display menu on the map
+ */
+ displayMapMenu: function(e) {
+ if (methods.hidePopup()) return;
+ if ($('#chimere_map_menu').is(":visible")){
+ $('#chimere_map_menu').hide();
+ } else{
+ settings.current_position =
+ settings.map.getLonLatFromViewPortPx(e.xy);
+ var offsetX = e.pageX;
+ var offsetY = e.pageY;
+ $('#chimere_map_menu').show('fast');
+ $('#chimere_map_menu').css('display', 'block');
+ $('#chimere_map_menu').css('top', offsetY);
+ $('#chimere_map_menu').css('left', offsetX);
+ }
+ },
+
/*
* Load markers and route from DB
*/
@@ -289,7 +371,13 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
category_element.parent().find("li input").attr("checked", val);
}
var _toggle_categories = function (subcategory_element) {
- var parent = subcategory_element.parent().parent().parent();
+ var parent = subcategory_element.closest('ul');
+ var parent_label = parent.parent().find("> span > label");
+ if (parent.find('input[type=checkbox]:checked').length){
+ parent_label.addClass('category-selected');
+ } else {
+ parent_label.removeClass('category-selected');
+ }
var master_check = parent.find("> input");
if (parent.find('.subcategories input[type=checkbox]').length ==
parent.find('.subcategories input[type=checkbox]:checked').length){
@@ -297,6 +385,14 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
} else {
master_check.removeAttr('checked');
}
+
+ if($('#action-categories').length){
+ if ($('#categories input[type=checkbox]:checked').length){
+ $('#action-categories').addClass('category-selected');
+ } else {
+ $('#action-categories').removeClass('category-selected');
+ }
+ }
return master_check;
};
var _init_categories = function () {
@@ -353,7 +449,7 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
EPSG_PROJECTION),
{icon:iconclone});
feature.pk = mark.properties.pk;
- feature.popupClass = OpenLayers.Popup.FramedCloud;
+ feature.popupClass = settings.popupClass;
feature.data.popupContentHTML = "<div class='cloud'>";
feature.data.popupContentHTML += mark.properties.name;
feature.data.popupContentHTML += "</div>";
@@ -363,7 +459,7 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
var _popup = function() {
/* show the popup */
if (settings.current_popup != null) {
- settings.current_popup.hide();
+ settings.current_popup.hide();
}
if (feature.popup == null) {
feature.popup = feature.createPopup();
@@ -373,32 +469,49 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
}
settings.current_popup = feature.popup;
/* hide on click on the cloud */
- settings.current_popup.groupDiv.onclick = methods.hidePopup;
+ if (!settings.explicit_popup_hide){
+ settings.current_popup.groupDiv.onclick = methods.hidePopup;
+ }
settings.permalink.updateLink();
}
+ var _repan_popup = function(){
+ /* re-pan manually */
+
+ // no clean way to detect if all the element are ready
+ // lack of better...
+ setTimeout(
+ function(){
+ settings.current_popup.panIntoView();
+ }, 1000);
+ }
+
var markerClick = function (evt) {
settings.current_feature = feature;
+ settings.current_position = feature.lonlat;
if ( settings.on_marker_click ) {
settings.on_marker_click(evt, mark, settings);
}
else
{
+ methods.center_on_feature();
+ $('#chimere_map_menu').hide();
// Default popup
if (feature.popup && feature.popup.visible()) {
if (settings.current_popup == feature.popup) {
feature.popup.hide();
if (!settings.simple){
- $('#panel').removeClass('panel-minified');
$('#detail').hide();
}
} else {
settings.current_popup.hide();
_popup();
methods.display_feature_detail(feature.pk);
+ _repan_popup();
}
} else {
_popup();
methods.display_feature_detail(feature.pk);
+ _repan_popup();
}
}
OpenLayers.Event.stop(evt);
@@ -448,6 +561,171 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
settings.current_feature.geometry = linestring;
settings.layerVectors.addFeatures([settings.current_feature]);
},
+ routingInputChange: function(){
+ $('#map_menu_clear').show();
+ if ($('#nominatim_start_lon').val()){
+ settings.routing_start = new OpenLayers.Marker(
+ new OpenLayers.LonLat($('#nominatim_start_lon').val(),
+ $('#nominatim_start_lat').val()
+ ).transform(EPSG_DISPLAY_PROJECTION,
+ settings.map.getProjectionObject()),
+ settings.icon_start);
+ settings.layerRouteMarker.addMarker(settings.routing_start);
+ }
+ if ($('#nominatim_end_lon').val()){
+ settings.routing_end = new OpenLayers.Marker(
+ new OpenLayers.LonLat($('#nominatim_end_lon').val(),
+ $('#nominatim_end_lat').val()
+ ).transform(EPSG_DISPLAY_PROJECTION,
+ settings.map.getProjectionObject()),
+ settings.icon_end);
+ settings.layerRouteMarker.addMarker(settings.routing_end);
+ }
+ if (settings.routing_end && settings.routing_start
+ && $('#search_routing').length) {
+ $('#search_routing').button('enable');
+ }
+ },
+
+ // set the start point for routing
+ routingFrom: function(){
+ $('#chimere_map_menu').hide();
+ settings.routing_panel_open();
+ $('#map_menu_clear').show();
+ settings.routing_start = new OpenLayers.Marker(
+ settings.current_position.clone(),
+ settings.icon_start);
+ settings.layerRouteMarker.addMarker(settings.routing_start);
+ if (nominatim_url){
+ helpers.updateNominatimName(settings.current_position.clone()
+ .transform(settings.map.getProjectionObject(),
+ EPSG_DISPLAY_PROJECTION),
+ 'start_label');
+ }
+ if (settings.routing_end) methods.route();
+ },
+ // add a step point for routing
+ routingAddStep: function(){
+ $('#chimere_map_menu').hide();
+ settings.routing_panel_open();
+ $('#map_menu_clear').show();
+ settings.routing_steps.push(new OpenLayers.Marker(
+ settings.current_position.clone(),
+ settings.icon_step.clone()));
+ settings.layerRouteMarker.addMarker(
+ settings.routing_steps[settings.routing_steps.length-1]);
+ if (settings.routing_end && settings.routing_start) methods.route();
+ },
+
+ // set the finish point for routing
+ routingTo: function(){
+ $('#chimere_map_menu').hide();
+ settings.routing_panel_open();
+ $('#map_menu_clear').show();
+ settings.routing_end = new OpenLayers.Marker(
+ settings.current_position.clone(),
+ settings.icon_end);
+ settings.layerRouteMarker.addMarker(settings.routing_end);
+ if (nominatim_url){
+ helpers.updateNominatimName(settings.current_position.clone()
+ .transform(settings.map.getProjectionObject(),
+ EPSG_DISPLAY_PROJECTION),
+ 'end_label');
+ }
+ if (settings.routing_start) methods.route();
+ },
+
+ // clear the current itinerary
+ routingClear: function(){
+ $('#nominatim_start_lon').val('');
+ $('#nominatim_start_lat').val('');
+ $('#nominatim_start_label').html('');
+ $('#chimere_start_label').html('');
+ $('#nominatim_end_lon').val('');
+ $('#nominatim_end_lat').val('');
+ $('#nominatim_end_label').html('');
+ $('#chimere_end_label').html('');
+ $('.nominatim-widget').val(default_nominatim_lbl);
+ $('#chimere_map_menu').hide();
+ $('#map_menu_clear').hide();
+ $('#chimere_itinerary').hide();
+ $('#chimere_itinerary_form').show();
+ if($('#search_routing').length) $('#search_routing').button('disable');
+ settings.layerRoute.removeAllFeatures();
+ settings.layerRouteMarker.clearMarkers();
+ settings.routing_start = null;
+ settings.routing_end = null;
+ settings.routing_steps = new Array();
+ },
+
+ // display a route
+ route: function(){
+ if($('#search_routing').length) $('#search_routing').button('enable');
+ if (!settings.routing_start || !settings.routing_end){
+ return;
+ }
+ var steps = [settings.routing_start.lonlat.clone()]
+ for (var i = 0; i < settings.routing_steps.length; i++) {
+ steps.push(settings.routing_steps[i].lonlat.clone());
+ }
+ steps.push(settings.routing_end.lonlat.clone());
+ // create the appropriate URL
+ var uri = extra_url + "route/"
+ var transport = $('input:radio[name=transport]:checked').val();
+ uri += transport + "/"
+ for (var i = 0; i < steps.length; i++) {
+ var step = steps[i].transform(
+ settings.map.getProjectionObject(),
+ EPSG_DISPLAY_PROJECTION);
+ if (i > 0){
+ uri += '_';
+ }
+ uri += step.lon + '_' + step.lat;
+ }
+ $.ajax({url: uri,
+ dataType: "json",
+ success: function (data) {
+ settings.layerRoute.removeAllFeatures();
+ for (var i = 0; i < data.features.length; i++) {
+ methods.putRoute(data.features[i]);
+ }
+ settings.map.zoomToExtent(
+ settings.layerRoute.getDataExtent());
+ settings.map.zoomOut();
+ $('#chimere_total_label').html(
+ data.properties.total);
+ $('#chimere_itinerary_content').html(
+ data.properties.description);
+ $('#chimere_itinerary').show();
+ $('#chimere_itinerary_form').hide();
+ settings.routing_panel_open();
+ },
+ error: function (data) {
+ settings.layerRoute.removeAllFeatures();
+ }
+ });
+
+ },
+ /*
+ Put a route on the map
+ */
+ putRoute: function(polyline) {
+ var point_array = new Array();
+ for (i=0; i<polyline.coordinates.length; i++){
+ var point = new OpenLayers.Geometry.Point(polyline.coordinates[i][0],
+ polyline.coordinates[i][1]);
+ point_array.push(point);
+ }
+ var linestring = new OpenLayers.Geometry.LineString(point_array);
+ linestring.transform(EPSG_DISPLAY_PROJECTION, settings.map.getProjectionObject());
+ current_route = new OpenLayers.Feature.Vector();
+ var style = OpenLayers.Util.extend({},
+ OpenLayers.Feature.Vector.style['default']);
+ style.strokeWidth = 3;
+ current_route.style = style;
+ current_route.geometry = linestring;
+ settings.layerRoute.addFeatures([current_route]);
+ },
display_feature_detail: function (pk) {
/*
* update current detail panel with an AJAX request
@@ -458,15 +736,14 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
var params = {}
if (settings.simple) { params["simple"] = 1; }
$.ajax({url: uri,
- data: params,
+ data: params,
success: function (data) {
if ( settings.display_feature_detail_fx ) {
// Custom function ?
settings.display_feature_detail_fx(data, settings);
}
else {
- if (!settings.simple) {
- $('#panel').addClass('panel-minified');
+ if (!settings.popupContentFull) {
$('#detail').html(data).show();
}
else {
@@ -508,9 +785,11 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
// Check if element is currently visible or not
var was_visible = $("#maincategory_" + id).is(":visible");
// Close all categories
- $("#categories ul.subcategories").hide();
+ if (settings.category_accordion){
+ $("#categories ul.subcategories").hide();
+ $("#categories img.toggle_category").attr("src", STATIC_URL + "chimere/img/plus.png");
+ }
// Put a minus image
- $("#categories img.toggle_category").attr("src", STATIC_URL + "chimere/img/plus.png");
if (!was_visible)
{
// Show the subcategories
@@ -519,6 +798,12 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
$("#maincategory_img_" + id).attr("src", STATIC_URL + "chimere/img/minus.png");
settings.current_category = id;
}
+ if (!settings.category_accordion && was_visible)
+ {
+ $("#maincategory_" + id).toggle();
+ // Put a minus image
+ $("#maincategory_img_" + id).attr("src", STATIC_URL + "chimere/img/plus.png");
+ }
},
zoomToCurrentExtent: function(){
/* zoom to current extent */
@@ -629,13 +914,16 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
else { // Default behaviour
if (settings.current_popup)
{
- settings.current_popup.hide();
if (!settings.simple){
- $('#panel').removeClass('panel-minified');
$('#detail').hide();
}
+ if (settings.current_popup.visible()){
+ settings.current_popup.hide();
+ return true;
+ }
}
}
+ return false;
},
saveExtent: function(){
var extent_key = 'MAP_EXTENT';
@@ -770,8 +1058,22 @@ OpenLayers.Layer.MapQuestOSM = OpenLayers.Class(OpenLayers.Layer.XYZ, {
if (vertices){
jQuery('#id_point').val(vertices);
}
+ },
+ updateNominatimName:function(lonlat, response_id){
+ $.ajax({
+ url: nominatim_url.substring(0, nominatim_url.length-6) + 'reverse',
+ data: {
+ format: "json",
+ lat:lonlat.lat,
+ lon:lonlat.lon
+ },
+ success: function (data) {
+ vals = $.parseJSON(data);
+ $('#nominatim_'+response_id).html(vals.display_name);
+ $('#chimere_'+response_id).html(vals.display_name);
+ }
+ });
}
-
}; // End of helpers
$.fn.chimere = function (thing) {
diff --git a/chimere/static/chimere/js/nominatim-widget.js b/chimere/static/chimere/js/nominatim-widget.js
new file mode 100644
index 0000000..e925cf2
--- /dev/null
+++ b/chimere/static/chimere/js/nominatim-widget.js
@@ -0,0 +1,42 @@
+var default_nominatim_lbl = '';
+$(function(){
+ $(".nominatim-widget").autocomplete({
+ source: function (request, response) {
+ $.ajax({
+ url: nominatim_url,
+ data: {
+ format: "json",
+ q: request.term,
+ },
+ success: function ( data ) {
+ response ( $.map( $.parseJSON(data), function( item ) {
+ return {
+ label: item.display_name,
+ value: item.display_name,
+ lat: item.lat,
+ lon: item.lon
+ }
+ }));
+
+ }
+ })
+ },
+ minLength: 6,
+ delay: 1000,
+ select: function ( event, ui ) {
+ $('#'+$(this).attr('id')+'_lat').val(ui.item.lat);
+ $('#'+$(this).attr('id')+'_lon').val(ui.item.lon);
+ $('#'+$(this).attr('id')+'_label').html(ui.item.label);
+ $('#chimere_'+$(this).attr('id').substring(10)+'_label').html(ui.item.label);
+ $('#'+$(this).attr('id')).val(default_nominatim_lbl);
+ jQuery("#map").chimere("routingInputChange");
+ return false;
+ },
+ open: function() {
+ $( this ).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
+ },
+ close: function() {
+ $( this ).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
+ }
+ });
+});
diff --git a/chimere/templates/base.html b/chimere/templates/base.html
index 2a50fc3..149cc71 100644
--- a/chimere/templates/base.html
+++ b/chimere/templates/base.html
@@ -7,25 +7,25 @@
{% endblock %}
</head>
<body {% block body_id %}{% endblock %} {% block body_class %}{% endblock %}>
- {% block extrabody %}
+{% block extrabody %}
+{% endblock %}
+{% block body %}
+<div id="header">
+ {% block header %}
{% endblock %}
- {% block body %}
- <div id="header">
- {% block header %}
- {% endblock %}
- </div>
- <div id="sidebar">
- {% block sidebar %}
- {% endblock %}
- </div>
- <div id="content">
- {% block content %}
- {% endblock %}
- </div>
- <div id="footer">
- {% block footer %}
- {% endblock %}
- </div>
+</div>
+<div id="sidebar">
+ {% block sidebar %}
{% endblock %}
+</div>
+<div id="content">
+ {% block content %}
+ {% endblock %}
+</div>
+<div id="footer">
+ {% block footer %}
+ {% endblock %}
+</div>
+{% endblock %}
</body>
</html>
diff --git a/chimere/templates/chimere/blocks/categories.html b/chimere/templates/chimere/blocks/categories.html
index 5ba89fc..9c5ffd6 100644
--- a/chimere/templates/chimere/blocks/categories.html
+++ b/chimere/templates/chimere/blocks/categories.html
@@ -1,29 +1,29 @@
{% load i18n %}
-<ul id='ul_categories'>
- {% for category, lst_sub_categories in sub_categories %}
- <li>
- <img class="control_image toggle_category" id="maincategory_img_{{category.id}}" alt="control" src="{{ STATIC_URL }}chimere/img/{% if category.selected %}minus.png{% else %}plus.png{% endif %}" />
- <input type="checkbox" id='checkall_{{category.id}}'>
- {% trans category.name %}
- <img id="zoom_to_category_{{category.id}}" class="zoom_image zoom_to_category" alt='{% trans "Zoom to" %} {{category.name}}' src='{{ STATIC_URL }}chimere/img/zoom.png' />
- <ul class='subcategories' id='maincategory_{{category.id}}'{% if not category.selected %} style='display:None'{% endif %}>
- {% for sub_category in lst_sub_categories %}
- <li id='li_sub_{{sub_category.id}}'>
- <input type='checkbox' name='category_{{sub_category.id}}' id='category_{{sub_category.id}}'{% if sub_category.selected %} checked='checked'{% endif %}/>
- <label for='category_{{sub_category.id}}'>
- <img alt='{{ sub_category.name }}' src='{{ MEDIA_URL }}{{sub_category.icon.image}}'/>
- {% trans sub_category.name %}
- </label>
- <img id="zoom_to_subcategory_{{sub_category.id}}" class="zoom_image zoom_to_subcategory" alt='{% trans "Zoom to" %} {{sub_category.name}}' src='{{ STATIC_URL }}chimere/img/zoom.png' />
- </li>
- {% endfor %}
- {% if category.description %}
- <li><a href="#" onclick="$('#map').chimere('category_detail', {{category.id}});">{% trans "Tell me more..." %}</a></li>
- {% endif %}
- </ul>
- </li>
- {% endfor %}
- <li id='display_submited'>
- <input type='checkbox' name='display_submited' id='display_submited_check'/> {% trans "Display markers and routes waiting for validation"%}
- </li>
-</ul>
+ <ul id='ul_categories'>
+ {% for category, lst_sub_categories in sub_categories %}
+ <li>
+ <img class="control_image toggle_category" id="maincategory_img_{{category.id}}" alt="control" src="{{ STATIC_URL }}chimere/img/{% if category.selected %}minus.png{% else %}plus.png{% endif %}" />
+ <input type="checkbox" id='checkall_{{category.id}}'>
+ {% trans category.name %}
+ <img id="zoom_to_category_{{category.id}}" class="zoom_image zoom_to_category" alt='{% trans "Zoom to" %} {{category.name}}' src='{{ STATIC_URL }}chimere/img/zoom.png' />
+ <ul class='subcategories' id='maincategory_{{category.id}}'{% if not category.selected %} style='display:None'{% endif %}>
+ {% for sub_category in lst_sub_categories %}
+ <li id='li_sub_{{sub_category.id}}'>
+ <input type='checkbox' name='category_{{sub_category.id}}' id='category_{{sub_category.id}}'{% if sub_category.selected %} checked='checked'{% endif %}/>
+ <label for='category_{{sub_category.id}}'>
+ <img alt='{{ sub_category.name }}' src='{{ MEDIA_URL }}{{sub_category.icon.image}}'/>
+ {% trans sub_category.name %}
+ </label>
+ <img id="zoom_to_subcategory_{{sub_category.id}}" class="zoom_image zoom_to_subcategory" alt='{% trans "Zoom to" %} {{sub_category.name}}' src='{{ STATIC_URL }}chimere/img/zoom.png' />
+ </li>
+ {% endfor %}
+ {% if category.description %}
+ <li><a href="#" onclick="$('#map').chimere('category_detail', {{category.id}});">{% trans "Tell me more..." %}</a></li>
+ {% endif %}
+ </ul>
+ </li>
+ {% endfor %}
+ <li id='display_submited'>
+ <input type='checkbox' name='display_submited' id='display_submited_check'/> {% trans "Display markers and routes waiting for validation"%}
+ </li>
+ </ul>
diff --git a/chimere/templates/chimere/blocks/head_form.html b/chimere/templates/chimere/blocks/head_form.html
new file mode 100644
index 0000000..2485c1a
--- /dev/null
+++ b/chimere/templates/chimere/blocks/head_form.html
@@ -0,0 +1,2 @@
+
+<script src="{{ TINYMCE_URL }}tiny_mce.js"></script>
diff --git a/chimere/templates/chimere/blocks/map_menu.html b/chimere/templates/chimere/blocks/map_menu.html
new file mode 100644
index 0000000..38fb4a8
--- /dev/null
+++ b/chimere/templates/chimere/blocks/map_menu.html
@@ -0,0 +1,14 @@
+{% load i18n %}
+<div id='chimere_map_menu'>
+ <ul>
+ {% if routing %}
+ <li id='map_menu_from' class='routing_item'>{% trans "From" context "routing" %}</li>
+ <li id='map_menu_step' class='routing_item'>{% trans "Add a step" context "routing" %}</li>
+ <li id='map_menu_to' class='routing_item'>{% trans "To" context "routing" %}</li>
+ <li id='map_menu_clear' class='routing_item'>{% trans "Clear the itinerary" context "routing" %}</li>
+ {% endif%}
+ <li id='map_menu_zoomin'>{% trans "Zoom in" %}</li>
+ <li id='map_menu_zoomout'>{% trans "Zoom out" %}</li>
+ <li id='map_menu_center'>{% trans "Center the map here" %}</li>
+ </ul>
+</div>
diff --git a/chimere/templates/chimere/blocks/map_params.html b/chimere/templates/chimere/blocks/map_params.html
index 57ced90..27762a3 100644
--- a/chimere/templates/chimere/blocks/map_params.html
+++ b/chimere/templates/chimere/blocks/map_params.html
@@ -7,6 +7,7 @@
chimere_init_options["map_layers"] = [{{map_layers|safe|escape}}];
chimere_init_options['permalink_label'] = '{%trans "Permalink"%}';
chimere_init_options['permalink_element'] = document.getElementById('permalink');
+ chimere_init_options['routing'] = {{routing}};
{% if dynamic_categories %}chimere_init_options['dynamic_categories'] = true;{% endif %}
{% if default_area %}
chimere_init_options["default_area"] = new Array({{default_area.upper_left_corner.x}}, {{default_area.upper_left_corner.y}}, {{default_area.lower_right_corner.x}}, {{default_area.lower_right_corner.y}});
diff --git a/chimere/templates/chimere/blocks/multimedia_file.html b/chimere/templates/chimere/blocks/multimedia_file.html
index a1e9868..d659348 100644
--- a/chimere/templates/chimere/blocks/multimedia_file.html
+++ b/chimere/templates/chimere/blocks/multimedia_file.html
@@ -1,6 +1,6 @@
{% load i18n %}
{% if multimedia_item.picture %}
-<a rel="prettyPhoto" href='{{multimedia_item.picture.url}}' ><img alt="{{multimedia_item.name}}" src='{{multimedia_item.thumbnailfile.url}}'/></a>{% endif %}
+<a rel="prettyPhoto" href='{{multimedia_item.picture.url}}' ><img class='thumbnail' alt="{{multimedia_item.name}}" src='{{multimedia_item.thumbnailfile.url}}'/></a>{% endif %}
{% if multimedia_item.url %}
{% if multimedia_item.multimedia_type.iframe %}
diff --git a/chimere/templates/chimere/blocks/routing.html b/chimere/templates/chimere/blocks/routing.html
new file mode 100644
index 0000000..639fd18
--- /dev/null
+++ b/chimere/templates/chimere/blocks/routing.html
@@ -0,0 +1,64 @@
+{% load i18n %}
+{% if routing %}
+{{itinerary_form.media}}
+<a href='#' id='routing_button' class='ui-widget ui-button ui-state-default ui-corner-all'>{% trans "Itinerary"%}</a>
+<div id='chimere_itinerary_panel'>
+ <div id='chimere_itinerary_form'>
+ {% for hidden in itinerary_form.hidden_fields %}
+ {{ hidden }}
+ {% endfor %}
+ {% for field in itinerary_form.visible_fields %}
+ {% if field.label %}<p><label for='{{field.auto_id}}'>{{ field.label }}</label></p>{%endif%}
+ <p>{{field}}</p>
+ {% endfor %}
+ <span id='search_routing'>{% trans "Search" %}</span>
+ </div>
+ <div id='chimere_itinerary'>
+ <div id='chimere_itinerary_action'>
+ <ul class='action'>
+ <li class='ui-widget ui-button ui-state-default ui-corner-all'>
+ <a href='#' id='chimere_itinerary_modify'>{% trans "Modify" %}</a>
+ </li>
+ <li class='ui-widget ui-button ui-state-default ui-corner-all'>
+ <a href='#' id='chimere_itinerary_new'>{% trans "New search" %}</a>
+ </li>
+ </ul>
+ </div>
+ <div class='itinerary_label' id='total_label_div'>
+ <span id='chimere_total_label'></span>
+ </div>
+ <div class='itinerary_label'>
+ <span class='label'>{% trans "Start:"%}</span> <span id='chimere_start_label'></span></div>
+ <div id='chimere_itinerary_content'>
+ </div>
+ <div class='itinerary_label'>
+ <span class='label'>{% trans "Finish:"%}</span> <span id='chimere_end_label'></span>
+ </div>
+ </div>
+</div>
+<script language='javascript' type='text/javascript'>
+$(document).ready(function() {
+ $('#chimere_itinerary_panel').dialog({
+ autoOpen: false,
+ position: [50, 50],
+ title: "{% trans "Itinerary" %}",
+ height: 360,
+ resizable: false
+ });
+ $('#search_routing').button({'disabled':true});
+ $('#routing_button').click(function(){
+ $('#chimere_itinerary_panel').dialog('open');
+ });
+ $('#chimere_itinerary_modify').click(function(){
+ $('#chimere_itinerary').hide();
+ $('#chimere_itinerary_form').show();
+ });
+ $('#chimere_itinerary_new').click(function(){
+ $('#map').chimere('routingClear');
+ });
+ $('#search_routing').click(function(){
+ $('#map').chimere('route');
+ });
+});
+</script>
+{% endif%}
diff --git a/chimere/templates/chimere/detail.html b/chimere/templates/chimere/detail.html
index 95e6a70..2bd55aa 100644
--- a/chimere/templates/chimere/detail.html
+++ b/chimere/templates/chimere/detail.html
@@ -29,10 +29,11 @@
{% if simple %}{% trans "Share on"%}{% for share_network in share_networks %}
<a href='{{share_network.1}}'>{{share_network.0}}</a>
{% endfor %}{%else%}
- <ul id='share'>
+ <ul class='share'>
<li>{% trans "Share"%}</li>{% for share_network in share_networks %}
<li><a href='{{share_network.1}}'><img src="{{share_network.2}}" alt="{{share_network.0}}"/></a></li>
{% endfor %}</ul>{% endif %}
+ <a href="{{modif_by_email}}">{% trans "Propose a modification" %}</a>
{% comment %}
<a href='{% if marker.route %}{% url chimere:editroute-item area_name_slash|default_if_none:"" marker.route.pk "" %}{%else%}{% url chimere:edit-item area_name_slash|default_if_none:"" marker.pk "" %}{%endif%}'>
{% trans "Submit a modification" %}
diff --git a/chimere/templates/chimere/main_map.html b/chimere/templates/chimere/main_map.html
index 5a49e46..4a53b3f 100644
--- a/chimere/templates/chimere/main_map.html
+++ b/chimere/templates/chimere/main_map.html
@@ -22,6 +22,7 @@
{% if areas_visible %}
{% display_areas %}
{% endif %}
+ {% routing %}
{% display_news news_visible %}
<div id='permalink' class='ui-widget ui-button ui-state-default ui-corner-all'></div>
</div>
@@ -34,6 +35,7 @@
<script type="text/javascript">
$("#main-map").show();
</script>
+ {% map_menu %}
{% map_params %}
{% endblock %}
{% block footer %}
diff --git a/chimere/templatetags/chimere_tags.py b/chimere/templatetags/chimere_tags.py
index 46fb422..a07dc44 100644
--- a/chimere/templatetags/chimere_tags.py
+++ b/chimere/templatetags/chimere_tags.py
@@ -111,6 +111,27 @@ def head_chimere(context):
}
return context_data
+@register.inclusion_tag('chimere/blocks/head_form.html')
+def head_form():
+ """
+ Manualy add forms header (necessary in case of ajax load)
+ """
+ context_data = {
+ "TINYMCE_URL": settings.TINYMCE_URL,
+ }
+ return context_data
+
+@register.inclusion_tag('chimere/blocks/map_menu.html', takes_context=True)
+def map_menu(context):
+ context_data = {'routing':settings.CHIMERE_ENABLE_ROUTING}
+ return context_data
+
+@register.inclusion_tag('chimere/blocks/routing.html', takes_context=True)
+def routing(context):
+ context_data = {'routing':settings.CHIMERE_ENABLE_ROUTING,
+ 'itinerary_form':context['itinerary_form']}
+ return context_data
+
@register.inclusion_tag('chimere/blocks/map_params.html', takes_context=True)
def map_params(context):
context_data = {}
@@ -118,6 +139,8 @@ def map_params(context):
context_data['icon_offset_y'] = settings.CHIMERE_ICON_OFFSET_Y
context_data['icon_width'] = settings.CHIMERE_ICON_WIDTH
context_data['icon_height'] = settings.CHIMERE_ICON_HEIGHT
+ context_data['routing'] = 'true' if settings.CHIMERE_ENABLE_ROUTING \
+ else 'none'
area_name = context['area_name'] if 'area_name' in context else 'area_name'
map_layers, default_area = get_map_layers(area_name)
context_data['map_layers'] = ", ".join(map_layers)
diff --git a/chimere/urls.py b/chimere/urls.py
index a232382..81263a0 100644
--- a/chimere/urls.py
+++ b/chimere/urls.py
@@ -51,6 +51,17 @@ if settings.CHIMERE_FEEDS:
LatestPOIsByZoneID(), name='feeds-areaid'),
)
+if settings.CHIMERE_ENABLE_ROUTING:
+ urlpatterns += patterns('chimere.views',
+ url(r'^(?P<area_name>[a-zA-Z0-9_-]*/)?route/'\
+ r'(?P<transport>(%s))/'
+ r'(?P<lon1>[-]?[0-9]+[.]?[0-9]*)_(?P<lat1>[-]?[0-9]+[.]?[0-9]*)_'\
+ r'(?P<lonlat_steps>([-]?[0-9]+[.]?[0-9]*_[-]?[0-9]+[.]?[0-9]*_)*)'\
+ r'(?P<lon2>[-]?[0-9]+[.]?[0-9]*)_(?P<lat2>[-]?[0-9]+[.]?[0-9]*)$' %
+ ('|'.join([key for key, lbl in settings.CHIMERE_ROUTING_TRANSPORT])),
+ 'route', name="route"),
+ )
+
urlpatterns += patterns('chimere.views',
url(r'^charte/?$', 'charte', name="charte"),
url(r'^(?P<area_name>[a-zA-Z0-9_-]+/)?contact/?$', 'contactus', name="contact"),
diff --git a/chimere/views.py b/chimere/views.py
index f10b7fa..157a52e 100644
--- a/chimere/views.py
+++ b/chimere/views.py
@@ -26,6 +26,7 @@ Views of the project
import datetime
from itertools import groupby
+import simplejson
from django.conf import settings
from django.core import serializers
@@ -47,7 +48,9 @@ from chimere.widgets import getMapJS, PointChooserWidget, \
RouteChooserWidget, AreaWidget
from chimere.forms import MarkerForm, RouteForm, ContactForm, FileForm, \
FullFileForm, MultimediaFileFormSet, PictureFileFormSet, notifySubmission,\
- notifyStaff, AreaForm
+ notifyStaff, AreaForm, RoutingForm, getStaffEmails
+
+from chimere.route import router
def get_base_uri(request):
base_uri = 'http://'
@@ -120,6 +123,8 @@ def index(request, area_name=None, default_area=None, simple=False):
if request.GET and 'lat' in request.GET \
and 'lon' in request.GET:
zoomout = None
+ if settings.CHIMERE_ENABLE_ROUTING:
+ response_dct['itinerary_form'] = RoutingForm()
response_dct.update({
'actions':actions, 'action_selected':('view',),
'error_message':'',
@@ -475,6 +480,11 @@ def getDetail(request, area_name, marker_id):
for network in settings.CHIMERE_SHARE_NETWORKS:
share_networks.append((network[0], network[1] % net_dct, network[2]))
response_dct['share_networks'] = share_networks
+ net_dct['to'] = ";".join(getStaffEmails())
+ if net_dct['to']:
+ net_dct["body"] = _(settings.CHIMERE_MODIF_EMAIL)
+ response_dct['modif_by_email'] = 'mailto:?to=%(to)s&subject='\
+ '%(text)s&body=%(body)s%(url)s' % net_dct
response_dct['dated'] = settings.CHIMERE_DAYS_BEFORE_EVENT \
and marker.start_date
return render_to_response('chimere/detail.html', response_dct,
@@ -635,6 +645,31 @@ def redirectFromTinyURN(request, area_name='', tiny_urn=''):
return redir
return HttpResponseRedirect(response_dct['extra_url'] + parameters)
+def route(request, area_name, lon1, lat1, lonlat_steps, lon2, lat2,
+ transport='foot'):
+ '''
+ Get the JSON for a route
+ '''
+ try:
+ lon1, lat1 = float(lon1), float(lat1)
+ lon2, lat2 = float(lon2), float(lat2)
+ steps = [float(lonlat) for lonlat in lonlat_steps.split('_') if lonlat]
+ # regroup by 2
+ steps = [(steps[i*2], steps[i*2+1]) for i in range(len(steps)/2)]
+ except ValueError:
+ return HttpResponse('no results')
+ jsons, desc, total = router.route(lon1, lat1, lon2, lat2, steps=steps,
+ transport=transport)
+ if not jsons:
+ return HttpResponse('no results')
+ jsonencoder = simplejson.JSONEncoder()
+ total = jsonencoder.encode(total)
+ desc = jsonencoder.encode(desc)
+ data = '{"properties":{"total":%s, "description":%s}, '\
+ '"type": "FeatureCollection", "features":[%s]}' % (total, desc,
+ ",".join(jsons))
+ return HttpResponse(data)
+
def rss(request, area_name=''):
'''
Redirect to RSS subscription page
diff --git a/chimere/widgets.py b/chimere/widgets.py
index 8e2b8ad..9bbe0d9 100644
--- a/chimere/widgets.py
+++ b/chimere/widgets.py
@@ -26,6 +26,9 @@ from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings
from django.contrib.gis.db import models
from django.contrib.gis.geos import fromstr
+from django.utils.html import conditional_escape
+from django.forms.widgets import RadioInput, RadioFieldRenderer
+from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _
@@ -100,6 +103,41 @@ class ChosenSelectWidget(forms.Select):
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
+ value = value or self.value
+ attrs = attrs or self.attrs
+ if 'id' in self.attrs:
+ label_for = ' for="%s_%s"' % (self.attrs['id'], self.index)
+ else:
+ label_for = ''
+ 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
+ super(ButtonSelectWidget, self).__init__(*args, **kwargs)
+
+ def render(self, *args, **kwargs):
+ 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']
+ return mark_safe(rendered)
+
class TextareaWidget(forms.Textarea):
"""
Manage the edition of a text using TinyMCE
@@ -108,6 +146,22 @@ class TextareaWidget(forms.Textarea):
js = ["%stiny_mce.js" % settings.TINYMCE_URL,
"%schimere/js/textareas.js" % settings.STATIC_URL,]
+ def render(self, *args, **kwargs):
+ rendered = super(TextareaWidget, self).render(*args, **kwargs)
+ rendered += u"""<script type='text/javascript'>
+tinyMCE.init({
+ mode : "textareas",
+ theme : "advanced",
+ relative_urls : false,
+ theme_advanced_buttons1 : "bold,italic,underline,strikethrough,separator,bullist,numlist,separator,hr,separator,link",
+ theme_advanced_buttons2 : "",
+ theme_advanced_buttons3 : "",
+ width : "250",
+ height: "75"
+});</script>
+"""
+ return mark_safe(rendered)
+
class DatePickerWidget(forms.TextInput):
"""
Manage the edition of dates.
@@ -121,6 +175,27 @@ class DatePickerWidget(forms.TextInput):
u"</script>\n" % kwargs['attrs']['id']
return mark_safe(rendered)
+class NominatimWidget(forms.TextInput):
+ class Media:
+ js = ["%schimere/js/nominatim-widget.js" % settings.STATIC_URL]
+ def render(self, name, value, attrs=None, area_name=''):
+ 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=""/>
+<label class='nominatim-label' id='nominatim_%(id)s_label'>&nbsp;</label>
+<script type='text/javascript'>
+var default_nominatim_lbl = "%(label)s";
+var nominatim_url = "%(nominatim_url)s";
+$("#nominatim_%(id)s").val(default_nominatim_lbl);
+$("#nominatim_%(id)s").click(function(){
+ $("#nominatim_%(id)s").val('');
+});
+</script>
+""" % {'id':name, 'nominatim_url':settings.NOMINATIM_URL,
+ 'label':_(u"Street, City, Country")}
+ return mark_safe(tpl)
+
class PointChooserWidget(forms.TextInput):
"""
Manage the edition of point on a map
diff --git a/example_project/locale/fr/LC_MESSAGES/django.po b/example_project/locale/fr/LC_MESSAGES/django.po
new file mode 100644
index 0000000..ac36871
--- /dev/null
+++ b/example_project/locale/fr/LC_MESSAGES/django.po
@@ -0,0 +1,47 @@
+# Chimère
+# Copyright (C) 2012
+# This file is distributed under the same license as the Chimère package.
+# Étienne Loks <etienne.loks@peacefrogs.net>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: 2.0\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2012-08-26 17:11+0200\n"
+"Last-Translator: Étienne Loks <etienne.loks@peacefrogs.net>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1)\n"
+
+#: settings.py:79
+msgid "Foot"
+msgstr "Marche"
+
+#: settings.py:80
+msgid "Bicycle"
+msgstr "À vélo"
+
+#: settings.py:81
+msgid "Motorcar"
+msgstr "En voiture"
+
+#: settings.py:84
+msgid "You are walking slowly"
+msgstr "Vous marchez lentement"
+
+#: settings.py:85
+msgid "You are walking pretty quickly"
+msgstr "Vous marchez plutôt vite"
+
+#: settings.py:86
+msgid "You are riding pretty slowly"
+msgstr "Vous conduisez plutôt lentement"
+
+#: settings.py:87
+msgid "You are riding pretty quickly"
+msgstr "Vous conduisez plutôt rapidement"
+
+#: settings.py:106
+msgid "Hello, I would like to propose you a modification about this item: "
+msgstr "Bonjour, je voudrais vous proposer une modification à propos de cet élément : "
diff --git a/example_project/settings.py b/example_project/settings.py
index dec2827..c878c88 100644
--- a/example_project/settings.py
+++ b/example_project/settings.py
@@ -5,6 +5,7 @@
# overload all theses settings in your local_settings.py file
import os
+_ = lambda s: s
DEBUG = False
TEMPLATE_DEBUG = DEBUG
@@ -72,10 +73,37 @@ CHIMERE_OSM_PASSWORD = 'test'
# encoding for shapefile import
CHIMERE_SHAPEFILE_ENCODING = 'ISO-8859-1'
+# enable routing in Chimère
+CHIMERE_ENABLE_ROUTING = False
+
+CHIMERE_ROUTING_TRANSPORT = (('foot', _(u"Foot")),
+ ('bicycle', _(u"Bicycle")),
+ ('motorcar', _(u"Motorcar")),
+ )
+
+CHIMERE_ROUTING_SPEEDS = {'foot':((3, _(u"You are walking slowly")),
+ (6, _(u"You are walking pretty quickly")),),
+ 'bicycle':((16, _(u"You are riding pretty slowly")),
+ (22, _(u"You are riding pretty quickly")),)
+ }
+
+# available routing engine: 'routino'
+CHIMERE_ROUTING_ENGINE = {
+ 'ENGINE': 'routino',
+ 'PATH': '/usr/local/src/web/bin/router',
+ 'DB_PATH': '/var/local/routino/',
+}
+
+NOMINATIM_URL = 'http://nominatim.openstreetmap.org/search'
+
# thumbnail
CHIMERE_THUMBS_SCALE_HEIGHT=250
CHIMERE_THUMBS_SCALE_WIDTH=None
+# length of short description
+CHIMERE_SHORT_DESC_LENGTH = 400
+
+CHIMERE_MODIF_EMAIL = _(u"""Hello, I would like to propose you a modification about this item: """)
ADMINS = (
# ('Your Name', 'your_email@domain.com'),