diff options
author | etienne <etienne@9215b0d5-fb2c-4bbd-8d3e-bd2e9090e864> | 2008-10-22 22:39:53 +0000 |
---|---|---|
committer | etienne <etienne@9215b0d5-fb2c-4bbd-8d3e-bd2e9090e864> | 2008-10-22 22:39:53 +0000 |
commit | 030ed86130fabc78695355021b5a0586df3e77b9 (patch) | |
tree | bd06e4842c67577829cd433d7621bd22dac12776 | |
download | Chimère-030ed86130fabc78695355021b5a0586df3e77b9.tar.bz2 Chimère-030ed86130fabc78695355021b5a0586df3e77b9.zip |
git-svn-id: http://www.peacefrogs.net/svn/chimere/trunk@1 9215b0d5-fb2c-4bbd-8d3e-bd2e9090e864
-rw-r--r-- | __init__.py | 0 | ||||
-rw-r--r-- | initial_data.json | 1 | ||||
-rw-r--r-- | locale/fr/LC_MESSAGES/django.po | 146 | ||||
-rw-r--r-- | main/__init__.py | 0 | ||||
-rw-r--r-- | main/actions.py | 15 | ||||
-rw-r--r-- | main/admin.py | 35 | ||||
-rw-r--r-- | main/forms.py | 77 | ||||
-rw-r--r-- | main/models.py | 163 | ||||
-rw-r--r-- | main/views.py | 106 | ||||
-rw-r--r-- | main/widgets.py | 97 | ||||
-rwxr-xr-x | manage.py | 11 | ||||
-rw-r--r-- | settings.py | 94 | ||||
-rw-r--r-- | static/edit_map.js | 117 | ||||
-rw-r--r-- | static/forms.css | 11 | ||||
-rw-r--r-- | static/main_map.js | 172 | ||||
-rw-r--r-- | static/styles.css | 150 | ||||
-rw-r--r-- | templates/base.html | 29 | ||||
-rw-r--r-- | templates/detail.html | 7 | ||||
-rw-r--r-- | templates/edit.html | 51 | ||||
-rw-r--r-- | templates/main_map.html | 23 | ||||
-rw-r--r-- | templates/submited.html | 9 | ||||
-rw-r--r-- | urls.py | 26 |
22 files changed, 1340 insertions, 0 deletions
diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/__init__.py diff --git a/initial_data.json b/initial_data.json new file mode 100644 index 0000000..e6261a2 --- /dev/null +++ b/initial_data.json @@ -0,0 +1 @@ +[{"pk": 13, "model": "auth.permission", "fields": {"codename": "add_logentry", "name": "Can add log entry", "content_type": 5}}, {"pk": 14, "model": "auth.permission", "fields": {"codename": "change_logentry", "name": "Can change log entry", "content_type": 5}}, {"pk": 15, "model": "auth.permission", "fields": {"codename": "delete_logentry", "name": "Can delete log entry", "content_type": 5}}, {"pk": 4, "model": "auth.permission", "fields": {"codename": "add_group", "name": "Can add group", "content_type": 2}}, {"pk": 10, "model": "auth.permission", "fields": {"codename": "add_message", "name": "Can add message", "content_type": 4}}, {"pk": 1, "model": "auth.permission", "fields": {"codename": "add_permission", "name": "Can add permission", "content_type": 1}}, {"pk": 7, "model": "auth.permission", "fields": {"codename": "add_user", "name": "Can add user", "content_type": 3}}, {"pk": 5, "model": "auth.permission", "fields": {"codename": "change_group", "name": "Can change group", "content_type": 2}}, {"pk": 11, "model": "auth.permission", "fields": {"codename": "change_message", "name": "Can change message", "content_type": 4}}, {"pk": 2, "model": "auth.permission", "fields": {"codename": "change_permission", "name": "Can change permission", "content_type": 1}}, {"pk": 8, "model": "auth.permission", "fields": {"codename": "change_user", "name": "Can change user", "content_type": 3}}, {"pk": 6, "model": "auth.permission", "fields": {"codename": "delete_group", "name": "Can delete group", "content_type": 2}}, {"pk": 12, "model": "auth.permission", "fields": {"codename": "delete_message", "name": "Can delete message", "content_type": 4}}, {"pk": 3, "model": "auth.permission", "fields": {"codename": "delete_permission", "name": "Can delete permission", "content_type": 1}}, {"pk": 9, "model": "auth.permission", "fields": {"codename": "delete_user", "name": "Can delete user", "content_type": 3}}, {"pk": 16, "model": "auth.permission", "fields": {"codename": "add_contenttype", "name": "Can add content type", "content_type": 6}}, {"pk": 17, "model": "auth.permission", "fields": {"codename": "change_contenttype", "name": "Can change content type", "content_type": 6}}, {"pk": 18, "model": "auth.permission", "fields": {"codename": "delete_contenttype", "name": "Can delete content type", "content_type": 6}}, {"pk": 25, "model": "auth.permission", "fields": {"codename": "add_category", "name": "Can add category", "content_type": 9}}, {"pk": 28, "model": "auth.permission", "fields": {"codename": "add_icon", "name": "Can add icon", "content_type": 10}}, {"pk": 34, "model": "auth.permission", "fields": {"codename": "add_marker", "name": "Can add marker", "content_type": 12}}, {"pk": 40, "model": "auth.permission", "fields": {"codename": "add_property", "name": "Can add property", "content_type": 14}}, {"pk": 37, "model": "auth.permission", "fields": {"codename": "add_propertymodel", "name": "Can add property model", "content_type": 13}}, {"pk": 31, "model": "auth.permission", "fields": {"codename": "add_subcategory", "name": "Can add sub category", "content_type": 11}}, {"pk": 26, "model": "auth.permission", "fields": {"codename": "change_category", "name": "Can change category", "content_type": 9}}, {"pk": 29, "model": "auth.permission", "fields": {"codename": "change_icon", "name": "Can change icon", "content_type": 10}}, {"pk": 35, "model": "auth.permission", "fields": {"codename": "change_marker", "name": "Can change marker", "content_type": 12}}, {"pk": 41, "model": "auth.permission", "fields": {"codename": "change_property", "name": "Can change property", "content_type": 14}}, {"pk": 38, "model": "auth.permission", "fields": {"codename": "change_propertymodel", "name": "Can change property model", "content_type": 13}}, {"pk": 32, "model": "auth.permission", "fields": {"codename": "change_subcategory", "name": "Can change sub category", "content_type": 11}}, {"pk": 27, "model": "auth.permission", "fields": {"codename": "delete_category", "name": "Can delete category", "content_type": 9}}, {"pk": 30, "model": "auth.permission", "fields": {"codename": "delete_icon", "name": "Can delete icon", "content_type": 10}}, {"pk": 36, "model": "auth.permission", "fields": {"codename": "delete_marker", "name": "Can delete marker", "content_type": 12}}, {"pk": 42, "model": "auth.permission", "fields": {"codename": "delete_property", "name": "Can delete property", "content_type": 14}}, {"pk": 39, "model": "auth.permission", "fields": {"codename": "delete_propertymodel", "name": "Can delete property model", "content_type": 13}}, {"pk": 33, "model": "auth.permission", "fields": {"codename": "delete_subcategory", "name": "Can delete sub category", "content_type": 11}}, {"pk": 19, "model": "auth.permission", "fields": {"codename": "add_session", "name": "Can add session", "content_type": 7}}, {"pk": 20, "model": "auth.permission", "fields": {"codename": "change_session", "name": "Can change session", "content_type": 7}}, {"pk": 21, "model": "auth.permission", "fields": {"codename": "delete_session", "name": "Can delete session", "content_type": 7}}, {"pk": 22, "model": "auth.permission", "fields": {"codename": "add_site", "name": "Can add site", "content_type": 8}}, {"pk": 23, "model": "auth.permission", "fields": {"codename": "change_site", "name": "Can change site", "content_type": 8}}, {"pk": 24, "model": "auth.permission", "fields": {"codename": "delete_site", "name": "Can delete site", "content_type": 8}}, {"pk": 2, "model": "auth.group", "fields": {"name": "moderator", "permissions": [34, 35, 36]}}, {"pk": 1, "model": "auth.group", "fields": {"name": "administrator", "permissions": [7, 8, 9, 25, 28, 34, 31, 26, 29, 35, 32, 27, 30, 36, 33]}}, {"pk": 9, "model": "contenttypes.contenttype", "fields": {"model": "category", "name": "category", "app_label": "main"}}, {"pk": 6, "model": "contenttypes.contenttype", "fields": {"model": "contenttype", "name": "content type", "app_label": "contenttypes"}}, {"pk": 2, "model": "contenttypes.contenttype", "fields": {"model": "group", "name": "group", "app_label": "auth"}}, {"pk": 10, "model": "contenttypes.contenttype", "fields": {"model": "icon", "name": "icon", "app_label": "main"}}, {"pk": 5, "model": "contenttypes.contenttype", "fields": {"model": "logentry", "name": "log entry", "app_label": "admin"}}, {"pk": 12, "model": "contenttypes.contenttype", "fields": {"model": "marker", "name": "marker", "app_label": "main"}}, {"pk": 4, "model": "contenttypes.contenttype", "fields": {"model": "message", "name": "message", "app_label": "auth"}}, {"pk": 1, "model": "contenttypes.contenttype", "fields": {"model": "permission", "name": "permission", "app_label": "auth"}}, {"pk": 14, "model": "contenttypes.contenttype", "fields": {"model": "property", "name": "property", "app_label": "main"}}, {"pk": 13, "model": "contenttypes.contenttype", "fields": {"model": "propertymodel", "name": "property model", "app_label": "main"}}, {"pk": 7, "model": "contenttypes.contenttype", "fields": {"model": "session", "name": "session", "app_label": "sessions"}}, {"pk": 8, "model": "contenttypes.contenttype", "fields": {"model": "site", "name": "site", "app_label": "sites"}}, {"pk": 11, "model": "contenttypes.contenttype", "fields": {"model": "subcategory", "name": "sub category", "app_label": "main"}}, {"pk": 3, "model": "contenttypes.contenttype", "fields": {"model": "user", "name": "user", "app_label": "auth"}}] diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 0000000..f9a779e --- /dev/null +++ b/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,146 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2008-10-06 20:39+0200\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: main/actions.py:15 +msgid "View" +msgstr "Voir" + +#: main/actions.py:15 +msgid "Add" +msgstr "Ajouter" + +#: main/models.py:16 main/models.py:28 main/models.py:39 main/models.py:66 +#: main/models.py:120 +msgid "Name" +msgstr "Nom" + +#: main/models.py:17 main/models.py:40 main/models.py:71 main/models.py:122 +msgid "Available" +msgstr "Disponible" + +#: main/models.py:18 main/models.py:42 main/models.py:121 +msgid "Order" +msgstr "Ordre" + +#: main/models.py:23 main/models.py:38 templates/edit.html:24 +msgid "Category" +msgstr "Catégorie" + +#: main/models.py:29 main/models.py:69 templates/edit.html:43 +msgid "Image" +msgstr "Image" + +#: main/models.py:33 main/models.py:41 +msgid "Icon" +msgstr "Icone" + +#: main/models.py:47 main/models.py:67 +msgid "Subcategory" +msgstr "Sous-catégorie" + +#: main/models.py:68 +msgid "Localisation" +msgstr "Localisation" + +#: main/models.py:70 +msgid "Submited" +msgstr "Soumis" + +#: main/models.py:72 +msgid "Disabled" +msgstr "Désactivé" + +#: main/models.py:76 +msgid "Status" +msgstr "État" + +#: main/models.py:84 main/models.py:144 +msgid "Point of interest" +msgstr "Point d'intérêt" + +#: main/models.py:123 +msgid "Text" +msgstr "Texte" + +#: main/models.py:124 +msgid "Long text" +msgstr "Texte long" + +#: main/models.py:125 +msgid "Password" +msgstr "Mot de passe" + +#: main/models.py:129 +msgid "Type" +msgstr "Type" + +#: main/models.py:134 main/models.py:146 +msgid "Property model" +msgstr "Modèle de propriété" + +#: main/models.py:147 +msgid "Value" +msgstr "Valeur" + +#: main/models.py:151 +msgid "Property" +msgstr "Propriété" + +#: main/widgets.py:71 +msgid "Latitude" +msgstr "Latitude" + +#: main/widgets.py:71 +msgid "Longitude" +msgstr "Longitude" + +#: templates/edit.html:15 templates/submited.html:7 +msgid "Add a new site" +msgstr "Ajouter un nouveau site" + +#: templates/edit.html:16 +msgid "indicates a mandatory field" +msgstr "indique un champs obligatoire" + +#: templates/edit.html:19 +msgid "Site name" +msgstr "Nom du site" + +#: templates/edit.html:38 +msgid "Point" +msgstr "Point" + +#: templates/edit.html:39 +msgid "Select a location for this new site" +msgstr "Choisissez une localisation pour ce nouveau site" + +#: templates/edit.html:54 +msgid "Propose" +msgstr "Proposez" + +#: templates/main_map.html:19 +msgid "Detail" +msgstr "Détail" + +#: templates/submited.html:8 +msgid "" +"Your proposition has been submited. A moderator will treat your submission " +"shortly. Thanks!" +msgstr "" +"Votre proposition a été soumise. Un modérateur va traiter votre proposition " +"sous peu. Merci !" diff --git a/main/__init__.py b/main/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/main/__init__.py diff --git a/main/actions.py b/main/actions.py new file mode 100644 index 0000000..385b53c --- /dev/null +++ b/main/actions.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +Actions available in the main interface +""" +from django.utils.translation import ugettext_lazy as _ +from django.contrib.auth import models + +main_path = 'chimere/' + +class Action: + def __init__(self, id, path, label): + self.id, self.path, self.label = id, main_path + path, label + +actions = [Action('view', '', _('View')), Action('edit', 'edit', _('Add'))] diff --git a/main/admin.py b/main/admin.py new file mode 100644 index 0000000..0ec485f --- /dev/null +++ b/main/admin.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +Settings for administration pages +""" + +from chimere.main.models import Category, Icon, SubCategory, Marker, \ + PropertyModel, Property +from chimere.main.widgets import PointChooserWidget +from chimere.main.forms import MarkerAdminForm +from django.contrib import admin + +class MarkerAdmin(admin.ModelAdmin): + """ + Specialized the Point field. + """ + search_fields = ("name",) + list_display = ('name', 'subcategory', 'status') + list_filter = ('status', 'subcategory') + form = MarkerAdminForm + + """ + def formfield_for_dbfield(self, db_field, **kwargs): + if db_field.name == 'point': + kwargs['widget'] = PointChooserWidget + return super(MarkerAdmin, self).formfield_for_dbfield(db_field, + **kwargs) +""" +# register of differents database fields +admin.site.register(Category) +admin.site.register(Icon) +admin.site.register(SubCategory) +admin.site.register(Marker, MarkerAdmin) +admin.site.register(PropertyModel) +admin.site.register(Property) diff --git a/main/forms.py b/main/forms.py new file mode 100644 index 0000000..2951c90 --- /dev/null +++ b/main/forms.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +Forms +""" +from django import forms +from django.contrib.gis.db import models + +from chimere.main.models import Marker, PropertyModel, Property + +class MarkerAdminForm(forms.ModelForm): + """ + Main form for marker + """ + # declare properties + for property in PropertyModel.objects.filter(available=True): + exec('property_%d_%d = forms.CharField(label="%s", widget=forms.%s, \ +required=False)' % (property.order, property.id, property.name, + PropertyModel.TYPE_WIDGET[property.type])) + class Meta: + model = Marker + + def __init__(self, *args, **keys): + """ + Custom initialization method in order to manage properties + """ + if 'instance' in keys and keys['instance']: + instance = keys['instance'] + property_dct = {} + for pm in PropertyModel.objects.filter(available=True): + property = instance.getProperty(pm) + if property: + property_dct[pm.getNamedId()] = property.value + if 'initial' in keys: + keys['initial'].update(property_dct) + else: + keys['initial'] = property_dct + super(MarkerAdminForm, self).__init__(*args, **keys) + + def save(self, *args, **keys): + """ + Custom save method in order to manage associeted properties + """ + new_marker = super(MarkerAdminForm, self).save(*args, **keys) + if 'status' not in self.cleaned_data: + new_marker.status = 'S' + new_marker.save() + # save each property + for propertymodel in PropertyModel.objects.filter(available=True): + properties = Property.objects.filter(marker=new_marker, + propertymodel=propertymodel) + # new property + if not properties: + new_property = Property.objects.create(marker=new_marker, + propertymodel=propertymodel, + value=self.cleaned_data['property_%d_%d' % ( + propertymodel.order, propertymodel.id)]) + new_property.save() + else: + # in case of multiple edition as the same time delete arbitrary + # the others + if len(properties) > 1: + for property in properties[1:]: + property.delete() + property = properties[0] + property.value = self.cleaned_data['property_%d_%d' % ( + propertymodel.order, propertymodel.id)] + property.save() + return new_marker + +class MarkerForm(MarkerAdminForm): + """ + Form for the edit page + """ + class Meta: + model = Marker + exclude = ('status',) diff --git a/main/models.py b/main/models.py new file mode 100644 index 0000000..6d673d8 --- /dev/null +++ b/main/models.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +Models description +""" +from django.utils.translation import ugettext_lazy as _ + +from django.contrib.gis.db import models +from django.contrib import admin + +from chimere import settings +from chimere.main.widgets import PointField + +class Category(models.Model): + """Category of Point Of Interest (POI) + """ + name = models.CharField(_("Name"), max_length=150) + available = models.BooleanField(_("Available")) + order = models.IntegerField(_("Order")) + def __unicode__(self): + return self.name + class Meta: + ordering = ["order"] + verbose_name = _("Category") + +class Icon(models.Model): + '''Icon + ''' + name = models.CharField(_("Name"), max_length=150) + image = models.ImageField(_("Image"), upload_to='icons') + def __unicode__(self): + return self.name + class Meta: + verbose_name = _("Icon") + +class SubCategory(models.Model): + '''Sub-category + ''' + category = models.ForeignKey(Category, verbose_name=_("Category")) + name = models.CharField(_("Name"), max_length=150) + available = models.BooleanField(_("Available")) + icon = models.ForeignKey(Icon, verbose_name=_("Icon")) + order = models.IntegerField(_("Order")) + def __unicode__(self): + return u"%s / %s" % (self.category.name, self.name) + class Meta: + ordering = ["category", "order"] + verbose_name = _("Subcategory") + + def getAvailable(): + '''Get list of tuples with first the category and second the associated + subcategories + ''' + sub_categories = {} + for sub_category in SubCategory.objects.filter(category__available=True, + available=True): + if sub_category.category not in sub_categories: + sub_categories[sub_category.category] = [] + sub_categories[sub_category.category].append(sub_category) + return [(category, sub_cats) for category, sub_cats \ + in sub_categories.items()] + getAvailable = staticmethod(getAvailable) + +class Marker(models.Model): + '''Marker for a POI + ''' + name = models.CharField(_("Name"), max_length=150) + subcategory = models.ForeignKey(SubCategory, verbose_name=_("Subcategory")) + point = PointField(_("Localisation")) + picture = models.ImageField(_("Image"), upload_to='upload', blank=True) + STATUS = (('S', _('Submited')), + ('A', _('Available')), + ('D', _('Disabled')),) + STATUS_DCT = {} + for key, label in STATUS: + STATUS_DCT[key] = label + status = models.CharField(_("Status"), max_length=1, choices=STATUS) + objects = models.GeoManager() + + def __unicode__(self): + return self.name + + class Meta: + ordering = ('subcategory__category', 'subcategory', 'status', 'name') + verbose_name = _("Point of interest") + + def getLatitude(self): + '''Return the latitude + ''' + return self.point.y + + def getLongitude(self): + '''Return the longitude + ''' + return self.point.x + + def getProperty(self, propertymodel, safe=None): + """Get the property of an associated property model. + If safe set to True, verify if the property is available + """ + if safe and not propertymodel.available: + return + try: + property = Property.objects.get(propertymodel=propertymodel, + marker=self) + except Property.DoesNotExist: + return + return property + + def getProperties(self): + """Get all the property availables + """ + properties = [] + for pm in PropertyModel.objects.filter(available=True): + property = self.getProperty(pm) + if property: + properties.append(property) + return properties + + def getGeoJSON(self): + '''Return a GeoJSON string + ''' + return """{"type":"Feature", "geometry":{"type":"Point", "crs": "EPSG:%(epsg)d", "coordinates":[%(longitude)s, %(latitude)s]}, "properties":{"pk": %(id)d, "name": "%(name)s", "icon_path":"%(icon_path)s"}}""" \ + % {'id':self.id, 'name':self.name, 'icon_path':self.subcategory.icon.image, +'latitude':self.getLatitude(), 'longitude':self.getLongitude(), +'epsg':settings.EPSG_PROJECTION} + +class PropertyModel(models.Model): + '''Model for a property + ''' + name = models.CharField(_("Name"), max_length=150) + order = models.IntegerField(_("Order")) + available = models.BooleanField(_("Available")) + TYPE = (('T', _('Text')), + ('L', _('Long text')), + ('P', _('Password'))) + TYPE_WIDGET = {'T':'TextInput', + 'L':'Textarea', + 'P':'PasswordInput'} + type = models.CharField(_("Type"), max_length=1, choices=TYPE) + def __unicode__(self): + return self.name + class Meta: + ordering = ('order',) + verbose_name = _("Property model") + + def getNamedId(self): + '''Get the name used as named id (easily sortable) + ''' + return 'property_%d_%d' % (self.order, self.id) + +class Property(models.Model): + '''Property for a POI + ''' + marker = models.ForeignKey(Marker, verbose_name=_("Point of interest")) + propertymodel = models.ForeignKey(PropertyModel, + verbose_name=_("Property model")) + value = models.CharField(_("Value"), max_length=1000) + def __unicode__(self): + return "%s : %s" % (str(self.propertymodel), self.value) + class Meta: + verbose_name = _("Property") + diff --git a/main/views.py b/main/views.py new file mode 100644 index 0000000..c0503ad --- /dev/null +++ b/main/views.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +Views of the project +""" + +import datetime + +from django.shortcuts import render_to_response +from django.http import HttpResponseRedirect, HttpResponse +from django.core import serializers + +from chimere import settings +from chimere.main.actions import actions +from chimere.main.models import SubCategory, PropertyModel, Marker +from chimere.main.widgets import getMapJS, PointChooserWidget, URL_OSM_JS +from chimere.main.forms import MarkerForm + +def index(request): + """ + Main page + """ + subcategories = SubCategory.getAvailable() + # by default all subcategories are checked + for cat, sub_cats in subcategories: + for sub_category in sub_cats: + sub_category.selected = True + extra_js = "" + for url in URL_OSM_JS + ["%smain_map.js" % settings.MEDIA_URL]: + extra_js += '<script src="%s"></script>\n' % url + response_dct = {'actions':actions, 'action_selected':'view', + 'error_message':'', + 'sub_categories':subcategories, + 'extra_head':extra_js + getMapJS(), + 'media_path':settings.MEDIA_URL, + } + return render_to_response('main_map.html', response_dct) + +def edit(request): + """ + Edition page + """ + # If the form has been submited + if request.method == 'POST': + form = MarkerForm(request.POST, request.FILES) + # All validation rules pass + if form.is_valid(): + marker = form.save() + # set the submited status + marker.status = 'S' + marker.save() + return HttpResponseRedirect('/chimere/submited') + else: + # An unbound form + form = MarkerForm() + # get the « manualy » declared_fields. Ie: properties + declared_fields = form.declared_fields.keys() + response_dct = {'actions':actions, 'action_selected':'edit', + 'error_message':'', + 'media_path':settings.MEDIA_URL, + 'form':form, + 'extra_head':form.media, + 'sub_categories':SubCategory.getAvailable(), + 'point_widget':PointChooserWidget().render('point', None), + 'properties':declared_fields + } + # manualy populate the custom widget + if 'subcategory' in form.data and form.data['subcategory']: + response_dct['current_category'] = int(form.data['subcategory']) + return render_to_response('edit.html', response_dct) + +def submited(request): + """ + Successful submission page + """ + response_dct = {'actions':actions, 'action_selected':'edit', + 'media_path':settings.MEDIA_URL,} + return render_to_response('submited.html', response_dct) + +def getDetail(request, marker_id): + ''' + Get the detail for a marker + ''' + try: + marker = Marker.objects.filter(id=int(marker_id), status='A')[0] + except (ValueError, IndexError): + return HttpResponse('no results') + response_dct= {'media_path':settings.MEDIA_URL, 'marker':marker} + return render_to_response('detail.html', response_dct) + +def getMarkers(request, category_ids): + ''' + Get the JSON for a marker + ''' + try: + query = Marker.objects.filter(status='A') + query = query.extra(where=['subcategory_id IN (%s)' % \ + ",".join(category_ids.split('_'))]) + except: + return HttpResponse('no results') + markers = list(query) + if not markers: + return HttpResponse('no results') + data = '{"type": "FeatureCollection", "features":[%s]}' % \ + ",".join([marker.getGeoJSON() for marker in markers]) + return HttpResponse(data) diff --git a/main/widgets.py b/main/widgets.py new file mode 100644 index 0000000..4f78fdc --- /dev/null +++ b/main/widgets.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +Extra widgets and fields +""" + +from django import forms +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext_lazy as _ + +from chimere import settings +from django.contrib.gis.db import models + +URL_OSM_JS = ["http://www.openlayers.org/api/OpenLayers.js", + "http://openstreetmap.org/openlayers/OpenStreetMap.js"] + +def getMapJS(): + '''Variable initialization for drawing the map + ''' + # projection, center and bounds definitions + js = u"epsg_display_projection = new OpenLayers.Projection('EPSG:%d');\n" %\ + settings.EPSG_DISPLAY_PROJECTION + js += u"epsg_projection = new OpenLayers.Projection('EPSG:%d');\n" % \ + settings.EPSG_PROJECTION + js += u"var centerLonLat = new OpenLayers.LonLat(%f,\ +%f).transform(epsg_display_projection, epsg_projection);\n" % \ + settings.DEFAULT_CENTER + js += u"var maxExtent = new OpenLayers.Bounds(%f, %f, %f, %f);\n" % \ + settings.MAP_BOUNDS + js += u"var media_path = '%s';\n" % settings.MEDIA_URL + js = u"""<script type="text/javascript"><!-- +%s// !--></script> +""" % js + return js + +class PointChooserWidget(forms.TextInput): + """ + Manage the edition of point on a map + """ + class Media: + css = { + "all": ("%sforms.css" % settings.MEDIA_URL,) + } + js = ["%sedit_map.js" % settings.MEDIA_URL] + URL_OSM_JS + + def render(self, name, value, attrs=None): + ''' + Render a map and latitude, longitude information field + ''' + val = '0' + value_x, value_y = 0, 0 + if value: + val = str(value) + if hasattr(value, 'x') and hasattr(value, 'y'): + value_x, value_y = value.x, value.y + elif isinstance(value, unicode) and value.startswith('POINT('): + try: + value_x, value_y = value.split('(')[1][:-1].split(' ') + value_x, value_y = float(value_x), float(value_y) + except: + value = None + else: + value = None + tpl = getMapJS() + tpl += u'<script src="%sedit_map.js"></script>\n' % settings.MEDIA_URL + tpl += u"""<div id='map_edit'></div> +<div id='live_lonlat'> +<p><label for='live_latitude'>%s</label>\ +<input type='texte' name='live_latitude' id='live_latitude' size='8' \ +disabled='true' value='%f'/></p> +<p><label for='live_longitude'>%s</label><input type='texte' \ +name='live_longitude' id='live_longitude' size='8' disabled='true' \ +value='%f'/></p> +</div> +<input type='hidden' name='%s' id='id_%s' value="%s"/> +""" % (_("Latitude"), value_y, _("Longitude"), value_x, name, name, val) + tpl += """<script type='text/javascript'><!-- +init(); +""" + if value: + tpl += '''var mylonlat = new OpenLayers.LonLat(%f,%f); +putMarker(mylonlat.transform(epsg_display_projection, + map.getProjectionObject()).clone()); +''' % (value_x, value_y) + tpl += """// --></script> +<hr class='spacer'/> +""" + return mark_safe(tpl) + +class PointField(models.PointField): + ''' + Set the widget for the form field + ''' + def formfield(self, **keys): + defaults = {'widget': PointChooserWidget} + keys.update(defaults) + return super(PointField, self).formfield(**keys) diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..bcdd55e --- /dev/null +++ b/manage.py @@ -0,0 +1,11 @@ +#!/usr/bin/python +from django.core.management import execute_manager +try: + import settings # Assumed to be in the same directory. +except ImportError: + import sys + sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) + sys.exit(1) + +if __name__ == "__main__": + execute_manager(settings) diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..322167b --- /dev/null +++ b/settings.py @@ -0,0 +1,94 @@ +# Django settings for chimere project. + +# GDAL path for GeoDjango +GDAL_LIBRARY_PATH = '/usr/local/lib/libgdal.so' + +ROOT_PATH = '/home/etienne/Documents/Prog/chimere/' + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +ADMINS = ( + # ('Your Name', 'your_email@domain.com'), +) + +MANAGERS = ADMINS + +DATABASE_ENGINE = 'postgresql_psycopg2' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'ado_mssql'. +DATABASE_NAME = 'ratatouille' # Or path to database file if using sqlite3. +DATABASE_USER = 'ratatouille' # Not used with sqlite3. +DATABASE_PASSWORD = 'wiki' # Not used with sqlite3. +DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3. +DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3. + +# Local time zone for this installation. Choices can be found here: +# http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE +# although not all variations may be possible on all operating systems. +# If running in a Windows environment this must be set to the same as your +# system time zone. +TIME_ZONE = 'Europe/Paris' + +# Language code for this installation. All choices can be found here: +# http://www.w3.org/TR/REC-html40/struct/dirlang.html#langcodes +# http://blogs.law.harvard.edu/tech/stories/storyReader$15 +LANGUAGE_CODE = 'fr-fr' + +SITE_ID = 1 + +# If you set this to False, Django will make some optimizations so as not +# to load the internationalization machinery. +USE_I18N = True + +# Absolute path to the directory that holds media. +# Example: "/home/media/media.lawrence.com/" +MEDIA_ROOT = ROOT_PATH + 'static/' + +# URL that handles the media served from MEDIA_ROOT. +# Example: "http://media.lawrence.com" +MEDIA_URL = '/chimere/static/' + +# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a +# trailing slash. +# Examples: "http://foo.com/media/", "/media/". +ADMIN_MEDIA_PREFIX = '/chimere/media/' + +# Make this unique, and don't share it with anybody. +SECRET_KEY = 'achanger_!ToChange!' + +# List of callables that know how to import templates from various sources. +TEMPLATE_LOADERS = ( + 'django.template.loaders.filesystem.load_template_source', + 'django.template.loaders.app_directories.load_template_source', +# 'django.template.loaders.eggs.load_template_source', +) + +MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.middleware.doc.XViewMiddleware', +) + +ROOT_URLCONF = 'chimere.urls' + +TEMPLATE_DIRS = ( + # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". + # Always use forward slashes, even on Windows. + # Don't forget to use absolute paths, not relative paths. + ROOT_PATH + 'templates', +) + +INSTALLED_APPS = ( + 'django.contrib.auth', + 'django.contrib.admin', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.sites', + 'chimere.main', +) + +# Wikimap specific +MAP_BOUNDS = (-20037508.34, -20037508.34, 20037508.34, 20037508.34) +DEFAULT_CENTER = (-1.679444, 48.114722) +EPSG_PROJECTION = 900913 +EPSG_DISPLAY_PROJECTION = 4326 diff --git a/static/edit_map.js b/static/edit_map.js new file mode 100644 index 0000000..5a9c997 --- /dev/null +++ b/static/edit_map.js @@ -0,0 +1,117 @@ +/* map edit */ + +/* availaible map layers */ +var layerMapnik = new OpenLayers.Layer.OSM.Mapnik('Mapnik'); +var layerMarkers = new OpenLayers.Layer.Markers('POIs'); + +/* default size and offset for icon */ +var size = new OpenLayers.Size(21, 25); +var offset = new OpenLayers.Pixel(-(size.w/2), -size.h); +var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png', size, offset); + +/* set a marker with a click on the map */ +var setMarker = function (event){ + event = event || window.event; + lonlat = layerMarkers.getLonLatFromViewPortPx(event.xy); + putMarker(lonlat); + OpenLayers.Event.stop(event); +} + +/* put the marker on the map and update latitude and longitude fields */ +var putMarker = function (lonlat){ + if (marker) { + layerMarkers.removeMarker(marker); + } + var marker = new OpenLayers.Marker(lonlat.clone(), icon); + layerMarkers.addMarker(marker); + lonlat = lonlat.clone().transform(map.getProjectionObject(), + epsg_display_projection); + document.getElementById('id_point').value = 'POINT(' + lonlat.lon + + ' ' + lonlat.lat + ')'; + document.getElementById('live_latitude').value = lonlat.lon; + document.getElementById('live_longitude').value = lonlat.lat; +} + +/* main initialisation function */ +function init(){ + map = new OpenLayers.Map ('map_edit', { + controls:[new OpenLayers.Control.Navigation(), + new OpenLayers.Control.PanZoomBar(), + new OpenLayers.Control.Attribution()], + maxExtent: maxExtent, + maxResolution: 156543.0399, + units: 'm', + projection: epsg_projection, + displayProjection: epsg_display_projection, + } ); + layerMarkers.setOpacity(0.5); + map.addLayers([layerMapnik, layerMarkers]); + map.events.register('click', map, setMarker); + map.setCenter(centerLonLat, 12); + +} + + +/* code for drag'n drop : delayed for further version of openlayers */ + +/* +function init_b(){ + init(); + + marker.events.register('mouseup', marker, releaseMarker); + marker.events.register('mousedown', marker, catchMarker); + marker.events.register('mouseover', marker, markerOver); + marker.events.register('mouseout', marker, markerOut); + + map.events.register('mousemove', map, onMouseMove); + map.events.register('moveend', map, onMoveEnd); +} + +var marker_catched = false; + +function catchMarker(event){ + marker_catched = true; + event = event || window.event; + OpenLayers.Event.stop(event); +} + +function releaseMarker(event){ + event = event || window.event; + if(marker_catched) { + marker_catched = false; + lonlat = layerMarkers.getLonLatFromViewPortPx(marker.icon.px); + marker.lonlat = lonlat; + document.getElementById('latitude').value = marker.lonlat.lat; + document.getElementById('longitude').value = marker.lonlat.lon; + } + OpenLayers.Event.stop(event); +} + +function onMouseMove(event) { + event = event || window.event; + if (!marker_catched) {return;} + marker.icon.px = null; + marker.icon.moveTo(new OpenLayers.Pixel(event.xy.x + delta_x, + event.xy.y + delta_y + 20)); + defLiveLatLon(); + lonlat = layerMarkers.getLonLatFromViewPortPx(marker.icon.px).transform(epsg_projection, epsg_display_projection); + live_longitude.value = lonlat.lon; + live_latitude.value = lonlat.lat; + OpenLayers.Event.stop(event); +} + +function onMoveEnd(event) { + event = event || window.event; + marker.icon.px = map.getPixelFromLonLat(marker.lonlat); + OpenLayers.Event.stop(event); +} + +var markerOver = function (evt) { + document.body.style.cursor='pointer'; + OpenLayers.Event.stop(evt); +}; +var markerOut = function (evt) { + document.body.style.cursor='auto'; + OpenLayers.Event.stop(evt); +}; +*/ diff --git a/static/forms.css b/static/forms.css new file mode 100644 index 0000000..e536e96 --- /dev/null +++ b/static/forms.css @@ -0,0 +1,11 @@ +#map_edit{ +border: 1px solid black; +width:700px; +height:400px; +float:left; +} + +#live_lonlat{ +margin:1em; +float:left; +}
\ No newline at end of file diff --git a/static/main_map.js b/static/main_map.js new file mode 100644 index 0000000..9bb703f --- /dev/null +++ b/static/main_map.js @@ -0,0 +1,172 @@ +/* main map */ + +/* availaible map layers */ +var layerMapnik = new OpenLayers.Layer.OSM.Mapnik('Classic'); +var cyclemap = new OpenLayers.Layer.OSM.CycleMap("Cycle map", { + displayOutsideMaxExtent: true, + wrapDateLine: true}); + +/* default size and offset for icon */ +var size = new OpenLayers.Size(21, 25); +var offset = new OpenLayers.Pixel(-(size.w/2), -size.h); + +/* define global variable */ +var markers = new Array(); +var layerMarkers; + +var currentPopup; +var currentFeature; +var clicked = false; + +/* show a popup */ +function showPop(feature) { + if (currentPopup != null) { + currentPopup.hide(); + } + if (feature.popup == null) { + feature.popup = feature.createPopup(); + map.addPopup(feature.popup); + } else { + feature.popup.toggle(); + } + currentPopup = feature.popup; +} + +/* load markers with an AJAX request */ +function loadMarkers(){ + /* get checked categories */ + inputs = window.document.forms["frm_categories"]; + var categories = ''; + for (var i = 0; i < inputs.length; i++) { + input = inputs[i]; + if (input.checked + && input.name.substring('category_'.length, 0) == 'category_'){ + id = input.name.substring('category_'.length, input.name.length); + if(categories) categories += '_'; + categories += id; + } + } + /* 0 stand for all categories */ + if (!categories) categories = '0'; + var uri = "/chimere/getMarkers/" + categories; + OpenLayers.loadURL(uri, '', this, setMarkers); +} + +/* update the marker layers from an http response GeoJSON */ +function setMarkers(response){ + if(layerMarkers) layerMarkers.destroy(); + if (response.responseText.indexOf('no results') == -1) { + /* clean the marker layer */ + if (currentPopup) { + currentPopup.hide(); + hideDetail(); + } + layerMarkers = new OpenLayers.Layer.Markers('POIs'); + map.addLayer(layerMarkers); + layerMarkers.setOpacity(0.8); + + var json = new OpenLayers.Format.JSON(); + var markers_pt = json.read(response.responseText); + /* load every marker */ + for (var i = 0; i < markers_pt.features.length; i++) { + putMarker(markers_pt.features[i]); + } + /* + var geojson = new OpenLayers.Format.GeoJSON(); + var markers_pt = geojson.read(response.responseText); + for (var i = 0; i < markers_pt.length; i++) { + putMarker2(markers_pt[i]); + }*/ + } +} + +/* put a marker on the map */ +function putMarker(mark) { + /* initialise a new feature with appropriate attribute for setting a + marker */ + lat = mark.geometry.coordinates[1]; + lon = mark.geometry.coordinates[0]; + iconclone = new OpenLayers.Icon(media_path + mark.properties.icon_path, + size, offset); + var feature = new OpenLayers.Feature(markers, + new OpenLayers.LonLat(lon, lat).transform(epsg_display_projection, + epsg_projection), + {icon:iconclone}); + /*feature.closeBox = false;*/ + feature.pk = mark.properties.pk; + feature.popupClass = OpenLayers.Class(OpenLayers.Popup.FramedCloud); + feature.data.popupContentHTML = "<div class='cloud'>" + mark.properties.name + "<br/> </div>"; + feature.data.overflow = 'hidden'; + var marker = feature.createMarker(); + + /* manage markers events */ + var markerClick = function (evt) { + currentFeature = this; + if (clicked) { + if (currentPopup == this.popup) { + this.popup.hide(); + clicked = false; + hideDetail(); + } else { + currentPopup.hide(); + showPop(this); + updateDetail(this.pk); + } + } else { + showPop(this); + clicked = true; + updateDetail(this.pk); + } + OpenLayers.Event.stop(evt); + }; + var markerOver = function (evt) { + document.body.style.cursor='pointer'; + OpenLayers.Event.stop(evt); + }; + var markerOut = function (evt) { + document.body.style.cursor='auto'; + OpenLayers.Event.stop(evt); + }; + marker.events.register('mousedown', feature, markerClick); + marker.events.register('mouseover', feature, markerOver); + marker.events.register('mouseout', feature, markerOut); + layerMarkers.addMarker(marker); + return feature; +} + +/* update current detail panel with an AJAX request */ +function updateDetail(pk){ + var uri = "/chimere/getDetail/" + pk; + OpenLayers.loadURL(uri, '', this, setDetail); +} + +/* update the detail panel from an http response */ +function setDetail(response){ + if (response.responseText.indexOf('no results') == -1) { + document.getElementById('detail_content').innerHTML = response.responseText; + } +} + +/* hide content of detail panel */ +function hideDetail(){ + document.getElementById('detail_content').innerHTML = ''; +} + +/* main initialisation function */ +function init(){ + /* set the main map */ + map = new OpenLayers.Map ('map', { + controls:[new OpenLayers.Control.Navigation(), + new OpenLayers.Control.PanZoomBar(), + new OpenLayers.Control.ScaleLine()], + maxExtent: maxExtent, + maxResolution: 156543.0399, + units: 'm', + projection: new OpenLayers.Projection('EPSG:4326') + }); + /*projection: new OpenLayers.Projection('EPSG:900913'), + displayProjection: new OpenLayers.Projection('EPSG:4326')*/ + map.addLayers([layerMapnik, cyclemap]); + loadMarkers(); + map.setCenter(centerLonLat, 12); +} diff --git a/static/styles.css b/static/styles.css new file mode 100644 index 0000000..a70c702 --- /dev/null +++ b/static/styles.css @@ -0,0 +1,150 @@ +body{ +background-color:#EEF; +font-family:arial; +font-size:80%; +} + +fieldset{ +background-color:#FFF; +-moz-border-radius: 10px; +-webkit-border-radius: 10px; +border-radius: 10px; +} + +legend{ +font-weight:bold; +color:purple; +} + +h2{ +font-size:16px; +text-align:center; +margin:0; +margin-bottom:10px; +padding:0; +width:100%; +background-color:white; +border:solid 1px purple; +-moz-border-radius: 4px; +-webkit-border-radius: 4px; +border-radius: 4px; +} + +hr.spacer{ +clear:both; +border:None; +} + +.edit label{ +display:block; +} + +ul#action{ +background-color:#EEF; +list-style-type:none; +margin:0; +padding:3px; +padding-left:0; +border-bottom:1px solid black; +} + +#action li{ +display:inline; +padding:3px; +margin-right:6px; +border:1px solid black; +-moz-border-radius: 4px 4px 0 0; +-webkit-border-radius: 4px 4px 0 0; +border-radius: 4px 4px 0 0; +} + +#action li#selected{ +background-color:#FFF; +border-top:solid 2px purple; +} + +#action a{ +text-decoration:None; +color:black; +} + +#panel{ +padding:6px 10px; +border: 1px solid black; +height:200px; +position:absolute; +z-index:5; +top:50px; +bottom:20px; +right:18px; +width:250px; +background-color:#FFF; +opacity:0.8; +-moz-border-radius:10px; +-webkit-border-radius:10px; +border-radius:10px; +} + +#detail{ +padding:6px 10px; +border: 1px solid black; +position:absolute; +z-index:5; +top:274px; +bottom:18px; +right:18px; +width:250px; +background-color:#FFF; +opacity:0.8; +-moz-border-radius:10px; +-webkit-border-radius:10px; +border-radius:10px; +} + +#detail_content{ +overflow:auto; +height:90%; +} + +#map{ +border: 1px solid black; +position:absolute; +top:40px; +bottom:8px; +left:8px; +right:8px; +} + +ul#categories{ +margin:0; +padding:0; +overflow:auto; +height:140px; +} + +ul#categories li{ +font-variant:small-caps; +list-style:none; +} + +ul#categories li li{ +font-variant:normal; +} + +ul#categories ul{ +margin:0; +padding:0; +} + +ul.subcategories img{ +height:20px; +} + +.errorlist{ +color:purple; +font-weight:bold; +} + +.fieldWrapper{ +padding:6px; +}
\ No newline at end of file diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..3f4e0ac --- /dev/null +++ b/templates/base.html @@ -0,0 +1,29 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head> + <title>{% block title %}Chimère{% endblock %}</title> + <link rel="stylesheet" href="{{ media_path }}styles.css" /> + <script type="text/javascript"><!-- + var media_path = '{{ media_path }}'; + // --></script> + {% block extra_head %}{{extra_head|safe}}{% endblock %} +</head> + +<body> + <div id="topbar"> + <ul id='action'> +{% for action in actions %} + <li{% ifequal action.id action_selected %} id='selected'{% endifequal %}><a href='/{{ action.path }}'>{{ action.label }}</a></li> +{% endfor %} + </ul> + </div> + <div id="sidebar"> + {% block sidebar %}{% endblock %} + </div> + <div id="content"> + {% block content %}{% endblock %} + </div> +</body> +</html> + diff --git a/templates/detail.html b/templates/detail.html new file mode 100644 index 0000000..465d775 --- /dev/null +++ b/templates/detail.html @@ -0,0 +1,7 @@ +{% load i18n %} +<h3>{{marker.name}}</h3> +<div>{%trans marker.subcategory.name%}</div> +{% if marker.picture %}<img src='{{media_path}}{{marker.picture}}' alt='{{marker.name}}'/>{%endif%} +<div>{% for property in marker.getProperties %} +<p id='{{property.propertymodel.getNamedId}}'>{{ property.value }}</p> +{% endfor %}</div>
\ No newline at end of file diff --git a/templates/edit.html b/templates/edit.html new file mode 100644 index 0000000..9d3ee8c --- /dev/null +++ b/templates/edit.html @@ -0,0 +1,51 @@ +{% extends "base.html" %} +{% load i18n %} +{% block sidebar %} +{% endblock %} + +{% block content %} +{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} +<fieldset class='edit'> +<legend>{% trans "Add a new site" %}</legend> +<p>* {% trans "indicates a mandatory field" %}</p> +<form enctype="multipart/form-data" method='post' action='/chimere/edit/'> +<div class="fieldWrapper"> + <label for="id_name">{% trans "Site name"%} *</label> + {{ form.name.errors }} + {{ form.name }} +</div> +<div class="fieldWrapper"> + <label for="id_subcategory">{% trans "Category" %} *</label> + {{ form.subcategory.errors }} + <select name='subcategory' id='subcategory'> + <option value="">---------</option> + {% for cat_subcat in sub_categories %} + <optgroup label="{{cat_subcat.0.name}}"> + {% for sub_category in cat_subcat.1 %} + <option value='{{sub_category.id}}'{% ifequal sub_category.id current_category %} selected='selected'{% endifequal %}> + {% trans sub_category.name %} + </option>{% endfor %} + </optgroup>{% endfor %} + </select> +</div> +<div class="fieldWrapper"> + <label for="id_point">{% trans "Point"%} *</label> + {%if form.point.errors %}<ul class="errorlist"><li>{% trans "Select a location for this new site" %}</li></ul>{%endif%} + {{form.point}} +</div> +<div class="fieldWrapper"> + <label for="id_picture">{% trans "Image" %}</label> + {{ form.picture.errors }} + {{ form.picture }} +</div> +{%for field in form%}{%for property in properties%}{%ifequal field.name property%} +<div class="fieldWrapper"> + <label for="id_{{field.name}}">{% trans field.label %}</label> + {{ field.errors }} + {{ field }} +</div> +{%endifequal%}{%endfor%}{%endfor%} +<p><input type='submit' value="{% trans 'Propose'%}"/></p> +</form> +</fieldset> +{% endblock %} diff --git a/templates/main_map.html b/templates/main_map.html new file mode 100644 index 0000000..3f43131 --- /dev/null +++ b/templates/main_map.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} +{% load i18n %} +{% block sidebar %} +<div id='panel'> +<form method='post' name='frm_categories' id='frm_categories'> +<ul id='categories'>{% for category, lst_sub_categories in sub_categories %} + <li>{% trans category.name %} + <ul class='subcategories'>{% for sub_category in lst_sub_categories %} + <li><input type='checkbox' onclick='loadMarkers()' name='category_{{sub_category.id}}' id='{{sub_category.id}}'{% if sub_category.selected %} checked='checked'{% endif %}/> <label for='{{sub_category.id}}'><img alt='{{sub_category.name}}' src='{{media_path}}{{sub_category.icon.image}}'/> {% trans sub_category.name %}</label></li>{% endfor %} + </ul> + </li>{% endfor %} +</ul> +</form> +</div> +<div id='detail'> +<h2>{% trans "Detail" %}</h2> +<div id='detail_content'> +</div> +</div>{% endblock %} +{% block content %}<div id='map'></div> +<script type='text/javascript'><!-- +init(); +// --> </script>{% endblock %} diff --git a/templates/submited.html b/templates/submited.html new file mode 100644 index 0000000..824bd7f --- /dev/null +++ b/templates/submited.html @@ -0,0 +1,9 @@ +{% extends "base.html" %} +{% load i18n %} +{% block content %} +<fieldset class='edit'> +<legend>{% trans "Add a new site" %}</legend> +<p>{% trans "Your proposition has been submited. A moderator will treat your submission shortly. Thanks!" %}</p> +</fieldset> +{% endblock %} + @@ -0,0 +1,26 @@ +from django.conf.urls.defaults import * + +from django.contrib import admin +admin.autodiscover() + +from settings import ROOT_PATH + +urlpatterns = patterns('', + # Example: + # (r'^chimere/', include('chimere.foo.urls')), + (r'^chimere/admin/(.*)', admin.site.root), + (r'^chimere/$', 'chimere.main.views.index'), + (r'^chimere/edit/$', 'chimere.main.views.edit'), + (r'^chimere/submited/$', 'chimere.main.views.submited'), + (r'^chimere/getDetail/(?P<marker_id>\d+)/$', + 'chimere.main.views.getDetail'), + (r'^chimere/getMarkers/(?P<category_ids>\w+)/$', + 'chimere.main.views.getMarkers'), + (r'^chimere/static/(?P<path>.*)$', 'django.views.static.serve', + {'document_root': 'static/'}), + (r'^chimere/static/(?P<path>.*)$', 'django.views.static.serve', + {'document_root': ROOT_PATH + 'static/'}), + (r'^chimere/media/(?P<path>.*)$', 'django.views.static.serve', + {'document_root': ROOT_PATH + 'media/'}), + +) |