diff options
author | Étienne Loks <etienne.loks@proxience.com> | 2014-12-30 16:59:44 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@proxience.com> | 2015-05-06 15:38:32 +0200 |
commit | 25ec2a9794786ac83fa8ce743078305682d8298d (patch) | |
tree | 52e8f0c1333377628b60f0feefad64861980519f | |
parent | 155b3890c7938e98f6c1596551260a92041bea68 (diff) | |
download | Ishtar-25ec2a9794786ac83fa8ce743078305682d8298d.tar.bz2 Ishtar-25ec2a9794786ac83fa8ce743078305682d8298d.zip |
Work on new town field (with state and department) - work on new UI for files
-rw-r--r-- | archaeological_files_pdl/forms.py | 56 | ||||
-rw-r--r-- | archaeological_files_pdl/templates/ishtar/wizard/wizard_instruction.html | 100 | ||||
-rw-r--r-- | archaeological_files_pdl/templates/ishtar/wizard/wizard_preventiveplanning.html | 77 | ||||
-rw-r--r-- | archaeological_files_pdl/views.py | 2 | ||||
-rw-r--r-- | archaeological_files_pdl/wizards.py | 17 | ||||
-rw-r--r-- | ishtar_common/forms_common.py | 8 | ||||
-rw-r--r-- | ishtar_common/static/media/style.css | 4 | ||||
-rw-r--r-- | ishtar_common/tasks.py | 35 | ||||
-rw-r--r-- | ishtar_common/templates/blocks/JQueryAdvancedTown.html | 99 | ||||
-rw-r--r-- | ishtar_common/templates/blocks/JQueryAdvancedTown.js | 1 | ||||
-rw-r--r-- | ishtar_common/urls.py | 4 | ||||
-rw-r--r-- | ishtar_common/views.py | 39 | ||||
-rw-r--r-- | ishtar_common/widgets.py | 101 | ||||
-rw-r--r-- | ishtar_common/wizards.py | 7 |
14 files changed, 537 insertions, 13 deletions
diff --git a/archaeological_files_pdl/forms.py b/archaeological_files_pdl/forms.py index 2703e52fd..295edcd36 100644 --- a/archaeological_files_pdl/forms.py +++ b/archaeological_files_pdl/forms.py @@ -21,13 +21,14 @@ import datetime from django import forms from django.core import validators +from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ -from ishtar_common.models import Person, valid_id +from ishtar_common.models import Person, PersonType, valid_id from archaeological_files import models from ishtar_common.forms import get_now, reverse_lazy -from ishtar_common.forms_common import get_town_field +from ishtar_common.forms_common import get_advanced_town_field from archaeological_files.forms import GENERAL_CONTRACTOR, \ RESPONSIBLE_PLANNING_SERVICE @@ -72,11 +73,14 @@ class FileFormPlanning(forms.Form): associated_models = {'town':models.Town} name = forms.CharField(label=_(u"Planning name"), required=False, max_length=100) - main_town = get_town_field(required=False) + main_town = get_advanced_town_field(required=True) locality = forms.CharField(label=_(u"Locality"), max_length=100, required=False) address = forms.CharField(label=_(u"Address (number/street)"), - widget=forms.Textarea, required=False) + widget=forms.Textarea( + attrs={"placeholder":_(u"Number/street")}), + required=False, + ) postal_code = forms.CharField(label=_(u"Postal code"), max_length=10, required=False) total_surface = forms.IntegerField(required=False, @@ -156,6 +160,8 @@ class FileFormGeneralContractor(forms.Form): class FileFormPlanningService(forms.Form): form_label = _(u"Town planning service") associated_models = {'responsible_planning_service':models.Person} + reference_number = forms.IntegerField(label=_(u"File reference"), + required=False) def __init__(self, *args, **kwargs): super(FileFormPlanningService, self).__init__(*args, **kwargs) @@ -170,4 +176,46 @@ class FileFormPlanningService(forms.Form): js_template='ishtar/blocks/JQueryCorporationPerson.js', new=True), validators=[valid_id(Person)]) + self.fields.keyOrder = ['responsible_planning_service', + 'reference_number'] + +class FileFormInstruction(forms.Form): + form_label = u"Instruction SRA" + in_charge = forms.IntegerField(label=_("Person in charge"), + widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person', + args=[PersonType.objects.get(txt_idx='sra_agent').pk]), + limit={'person_types':[PersonType.objects.get(txt_idx='sra_agent').pk]}, + associated_model=Person, new=True), + validators=[valid_id(Person)]) + related_file = forms.IntegerField(label=_("Related file"), required=False, + widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-file'), + associated_model=models.File), + validators=[valid_id(models.File)]) + comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea, + required=False) + year = forms.IntegerField(label=_("Year"), + validators=[validators.MinValueValidator(1900), + validators.MaxValueValidator(2100)]) + numeric_reference = forms.IntegerField(label=_("Numeric reference"), + required=False) + end_date = forms.DateField(initial=get_now, widget=widgets.JQueryDate, + required=False) + def __init__(self, *args, **kwargs): + c_year = datetime.date.today().year + if 'year' in kwargs: + c_year = kwargs.pop('year') + super(FileFormInstruction, self).__init__(*args, **kwargs) + self.fields['year'].initial = c_year + self.fields['year'].widget.attrs.update({'readonly':'readonly'}) + c_num, lasts = 0, "" + q = models.File.objects.filter(numeric_reference__isnull=False, + year=c_year).order_by('-numeric_reference') + if q.count(): + num = q.all()[0].numeric_reference + lasts = u"SRA %s-%d" % (unicode(c_year), num) + lbl = self.fields['numeric_reference'].label + if lasts: + lbl += u"<br/>(dernière entrée : %s)" % lasts + self.fields['numeric_reference'].label = mark_safe(lbl) + self.fields['numeric_reference'].initial = c_num + 1 diff --git a/archaeological_files_pdl/templates/ishtar/wizard/wizard_instruction.html b/archaeological_files_pdl/templates/ishtar/wizard/wizard_instruction.html new file mode 100644 index 000000000..b47de2cce --- /dev/null +++ b/archaeological_files_pdl/templates/ishtar/wizard/wizard_instruction.html @@ -0,0 +1,100 @@ +{% extends "ishtar/wizard/default_wizard.html" %} +{% load i18n range table_form %} +{% block wizard_form %} +<form action="." method="post" name='wizard'{% if wizard.form.file_upload %} enctype="multipart/form-data"{% endif %}>{% csrf_token %} +<div class='form'> +{{ wizard.form.media }} +{{ wizard.management_form }} + +<table> + +<tr class='required'> + <th><label for="id_instruction-{{CURRENT_ACTION}}-in_charge">Dossier suivi par</label></th> +</tr> +<tr class='required'> + <td>{{wizard.form.in_charge|safe}}</td> +</tr> + +<tr> + <th><label for="id_instruction-{{CURRENT_ACTION}}-related_file">Dossier lié à</label></th> +</tr> +<tr> + <td>{{wizard.form.related_file|safe}}</td> +</tr> + +<tr> + <th><label for="id_instruction-{{CURRENT_ACTION}}-comment">Commentaire</label></th> +</tr> +<tr> + <td>{{wizard.form.comment|safe}}</td> +</tr> + +<tr class='required'> + <th><label>État du dossier</label></th> +</tr> +<tr> + <td><input type='radio' name='state' value='open' id='state-open'/> <label for='state-open'>Dossier actif</label></td> +</tr> +<tr> + <td><input type='radio' name='state' value='closed' id='state-closed'/> <label for='state-closed'>Dossier clos / date de clôture</label> : {{wizard.form.end_date|safe}}</td> +</tr> + +<tr class='required'> + <th><label for="id_instruction-{{CURRENT_ACTION}}-year">{{wizard.form.numeric_reference.label}}</label></th> +</tr> +<tr> + <td>SRA <span class='small'>{{wizard.form.year|safe}}</span> - <span class='small'>{{wizard.form.numeric_reference|safe}}</span></td> +</tr> +</table> + +<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" /> +{{ previous_fields|safe }} +<div id='validation-bar'> + <input type="submit" id="submit_form" name='validate' value="{% trans "Validate" %}"/> + {% if next_steps %}<input type="submit" id="submit_end_form" name='validate_and_end' value="{% trans "Validate and end" %}"/>{% endif %} +</div> +</div> +</form> +<script type='text/javascript'> +$(function(){ + + if ($('#id_instruction-{{CURRENT_ACTION}}-end_date').val()){ + $("#state-closed").prop('checked', true); + } else { + $("#state-open").prop('checked', true); + } + + check_state = function(){ + var state = $("input[name=state]:checked").val(); + if (state == 'closed'){ + $('#id_instruction-{{CURRENT_ACTION}}-end_date').focus(); + $('#id_instruction-{{CURRENT_ACTION}}-end_date').prop('disabled', false); + } else if (state == 'open'){ + $('#id_instruction-{{CURRENT_ACTION}}-end_date').val(''); + $('#id_instruction-{{CURRENT_ACTION}}-end_date').prop('disabled', true); + } + }; + + $('input[name=state]').click(check_state); + + check_state(); + + $('#submit_form').click(function(){ + var state = $("input[name=state]:checked").val(); + if (state == 'closed'){ + if (!$('#id_instruction-{{CURRENT_ACTION}}-end_date').val()){ + alert("Vous devez sélectionner une date de clôture.") + return false; + } + return true; + } else if (state == 'open'){ + return true; + } else { + alert("Vous devez choisir un état pour ce dossier.") + return false; + } + return true; + }); +}); +</script> +{% endblock %} diff --git a/archaeological_files_pdl/templates/ishtar/wizard/wizard_preventiveplanning.html b/archaeological_files_pdl/templates/ishtar/wizard/wizard_preventiveplanning.html new file mode 100644 index 000000000..41527629d --- /dev/null +++ b/archaeological_files_pdl/templates/ishtar/wizard/wizard_preventiveplanning.html @@ -0,0 +1,77 @@ +{% extends "ishtar/wizard/default_wizard.html" %} +{% load i18n range table_form %} +{% block wizard_form %} +<form action="." method="post" name='wizard'{% if wizard.form.file_upload %} enctype="multipart/form-data"{% endif %}>{% csrf_token %} +<div class='form'> +{{ wizard.form.media }} +{{ wizard.management_form }} + +<table> + +<tr class='required'> + <th><label for="id_preventiveplanning-{{CURRENT_ACTION}}-name">Nom de l'aménagement</label></th> +</tr> +<tr class='required'> + <td>{{wizard.form.name|safe}}</td> +</tr> + +</table> + +<h4>Localisation</h4> +<table> + +<tr> + <td>{{wizard.form.main_town|safe}}</td> +</tr> + +<tr> + <th colspan='2'><label for="id_preventiveplanning-{{CURRENT_ACTION}}-locality">Lieu-dit</label></th> +</tr> +<tr> + <td colspan='2'>{{wizard.form.locality|safe}}</td> +</tr> + +<tr> + <th colspan='2'><label for="id_preventiveplanning-{{CURRENT_ACTION}}-address">Adresse</label></th> +</tr> +<tr> + <td colspan='2'>{{wizard.form.address|safe}}</td> +</tr> + +<tr> + <th colspan='2'><label for="id_preventiveplanning-{{CURRENT_ACTION}}-postal_code">Code postal</label></th> +</tr> +<tr> + <td colspan='2'>{{wizard.form.postal_code|safe}}</td> +</tr> + +</table> + +<h4>Surfaces</h4> +<table> + +<tr> + <th><label for="id_preventiveplanning-{{CURRENT_ACTION}}-total_surface">Surface totale des terrains</label></th> +</tr> +<tr> + <td>{{wizard.form.total_surface|safe}}</td> +</tr> + +<tr> + <th><label for="id_preventiveplanning-{{CURRENT_ACTION}}-total_developed_surface">Surface totale aménagée</label></th> +</tr> +<tr> + <td>{{wizard.form.total_developed_surface|safe}}</td> +</tr> + +</table> + +<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" /> +{{ previous_fields|safe }} +<div id='validation-bar'> + <input type="submit" id="submit_form" name='validate' value="{% trans "Validate" %}"/> + {% if next_steps %}<input type="submit" id="submit_end_form" name='validate_and_end' value="{% trans "Validate and end" %}"/>{% endif %} +</div> +</div> +</form> +{% endblock %} diff --git a/archaeological_files_pdl/views.py b/archaeological_files_pdl/views.py index 712990234..c8e1d1498 100644 --- a/archaeological_files_pdl/views.py +++ b/archaeological_files_pdl/views.py @@ -39,6 +39,8 @@ file_creation_wizard = FileWizard.as_view([ forms.FileFormGeneralContractor), ('planningservice-file_creation', forms.FileFormPlanningService), + ('instruction-file_creation', + forms.FileFormInstruction), ('research-file_creation', ref_forms.FileFormResearch), ('final-file_creation', ref_forms.FinalForm)], label=_(u"New file"), diff --git a/archaeological_files_pdl/wizards.py b/archaeological_files_pdl/wizards.py index 4abe5f0d5..6f688d7ca 100644 --- a/archaeological_files_pdl/wizards.py +++ b/archaeological_files_pdl/wizards.py @@ -25,12 +25,23 @@ class FileWizard(BaseFileWizard): town_input_id = 'main_town' multi_towns = False wizard_templates = { - 'generalcontractor-file_creation':\ - 'ishtar/wizard/wizard_generalcontractor.html',} + 'generalcontractor-%(url_name)s':\ + 'ishtar/wizard/wizard_generalcontractor.html', + 'instruction-%(url_name)s':\ + 'ishtar/wizard/wizard_instruction.html', + 'preventiveplanning-%(url_name)s':\ + 'ishtar/wizard/wizard_preventiveplanning.html', + } + + def get_current_year(self): + general_form_key = 'general-' + self.url_name + return self.session_get_value(general_form_key, 'year') def get_form_kwargs(self, *args, **kwargs): returned = super(FileWizard, self).get_form_kwargs(*args, **kwargs) - if args and args[0].startswith('generalcontractor-file_creation'): + if args and args[0].startswith('generalcontractor-'): if 'status' in self.request.GET: returned['status'] = self.request.GET['status'] + if args and args[0].startswith('instruction-'): + returned['year'] = self.get_current_year() return returned diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py index e1a0e9063..23d7126c9 100644 --- a/ishtar_common/forms_common.py +++ b/ishtar_common/forms_common.py @@ -54,6 +54,14 @@ def get_town_field(label=_(u"Town"), required=True): validators=[models.valid_id(models.Town)], label=label, help_text=mark_safe(help_text), required=required) +def get_advanced_town_field(label=_(u"Town"), required=True): + # !FIXME hard_link, reverse_lazy doen't seem to work with formsets + return forms.IntegerField( + widget=widgets.JQueryTown("/" + settings.URL_PATH + \ + 'autocomplete-advanced-town'), + validators=[models.valid_id(models.Town)], label=label, + required=required) + def get_person_field(label=_(u"Person"), required=True, person_types=[]): # !FIXME hard_link, reverse_lazy doen't seem to work with formsets widget = None diff --git a/ishtar_common/static/media/style.css b/ishtar_common/static/media/style.css index 55bb95e30..a1b084002 100644 --- a/ishtar_common/static/media/style.css +++ b/ishtar_common/static/media/style.css @@ -906,6 +906,10 @@ a.remove{ width:60px; } +.small, .small input{ + width:60px; +} + #progress{ display:none; position:fixed; diff --git a/ishtar_common/tasks.py b/ishtar_common/tasks.py index a9db26087..a8db97bb1 100644 --- a/ishtar_common/tasks.py +++ b/ishtar_common/tasks.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (C) 2013 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2013-2014 É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 Affero General Public License as @@ -17,13 +17,15 @@ # See the file COPYING for details. +import sys + from django.conf import settings from django.db.models import Q -from geodjangofla.models import Commune -from ishtar_common.models import Town +from ishtar_common.models import Town, Department def load_towns(): + from geodjangofla.models import Commune q = None for dpt_number in settings.ISHTAR_DPTS: query = Q(insee_com__istartswith=dpt_number) @@ -51,3 +53,30 @@ def load_towns(): setattr(town, k, defaults[k]) town.save() return nb, updated + +def update_towns(): + nb, updated = 0, 0 + dpts = dict([(dpt.number, dpt) for dpt in Department.objects.all()]) + q = Town.objects.filter(numero_insee__isnull=False) + total = q.count() + for idx, town in enumerate(q.all()): + sys.stdout.write('\rProcessing... %s/%d' % ( + str(idx+1).zfill(len(str(total))), total)) + if len(town.numero_insee) < 2: + continue + dpt_code = town.numero_insee[:2] + if dpt_code.startswith('9') and int(dpt_code) > 95: + dpt_code = town.numero_insee[:3] + if dpt_code not in dpts: + sys.stdout.write('Missing department with INSEE code: %s' % dpt_code) + continue + if town.departement == dpts[dpt_code]: + continue + if town.departement: + updated += 1 + else: + nb += 1 + town.departement = dpts[dpt_code] + town.save() + sys.stdout.write('\n') + return nb, updated diff --git a/ishtar_common/templates/blocks/JQueryAdvancedTown.html b/ishtar_common/templates/blocks/JQueryAdvancedTown.html new file mode 100644 index 000000000..78d2d7831 --- /dev/null +++ b/ishtar_common/templates/blocks/JQueryAdvancedTown.html @@ -0,0 +1,99 @@ +{% load i18n %}{% load url from future %}</td></tr> +<tr> + <td>{% trans "State" context "Région" %}</td> + <td> + <select id='current-state'> + <option value=''>--------</option>{% for state in states %} + <option value='{{state.number}}'{% if state.number == selected_state %}selected='selected'{% endif %}>{{state}}</option> + {% endfor %}</select> + </td> +</tr> +<tr> + <td>{% trans "Department" %}</td> + <td> + <select id='current-department'> + </select> + </td> +</tr> +<tr class='required'> + <th><label>{% trans "Town" %}</label></th> + <td><input{{attrs_select}}/> +<input type="hidden"{{attrs_hidden}}/> +<script type="text/javascript"><!--// + selected_department = "{{selected_department}}"; + var empty_select = "<option value=''>--------</option>"; + + function update_department_field(){ + var selected_state = $("#current-state").val(); + if (!selected_state){ + $("#current-department").html("<option value=''>"+"{% trans 'Choose a state first' %}"+"</option>"); + $("#current-department").prop('disabled', true); + $('#id_select_{{field_id}}').prop('disabled', true); + return; + } + $.ajax({ + url: "{% url 'department-by-state' %}" + selected_state, + type: 'get', + dataType: 'json', + success: function(data) { + var html = ""; + for (idx in data){ + dpt = data[idx]; + html += "<option value='" + dpt.number + "'"; + if (String(dpt.number) == String(selected_department)){ + html += " selected='selected'"; + } + html += ">" + dpt.value + "</option>"; + } + $("#current-department").html(html); + $("#current-department").prop('disabled', false); + update_search_town(); + } + }); + } + + function update_search_town(){ + selected_department = $("#current-department").val(); + if (selected_department){ + $("#id_select_{{field_id}}").autocomplete( "option", "source", {{source}}+selected_department); + $('#id_select_{{field_id}}').prop('disabled', false); + } else { + $('#id_select_{{field_id}}').prop('disabled', true); + } + } + + function empty_town(){ + $('#id_{{field_id}}').val(null); + $('#id_select_{{field_id}}').val(null); + } + + $(function() { + update_department_field(); + + $("#current-state").change(function(){ + empty_town(); + update_department_field(); + }); + + $("#current-department").change(function(){ + empty_town(); + update_search_town(); + }); + + $("#id_select_{{field_id}}").autocomplete({ + source: {{source}}, + select: function( event, ui ) { + if(ui.item){ + $('#id_{{field_id}}').val(ui.item.id); + } else { + $('#id_{{field_id}}').val(null); + } + }, + minLength: 2{% if options %}, + {{options}} + {% endif %} + }); + + $('#id_select_{{field_id}}').live('click', empty_town); + +});//--></script> diff --git a/ishtar_common/templates/blocks/JQueryAdvancedTown.js b/ishtar_common/templates/blocks/JQueryAdvancedTown.js new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/ishtar_common/templates/blocks/JQueryAdvancedTown.js @@ -0,0 +1 @@ + diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py index d31d0d359..0c4059eeb 100644 --- a/ishtar_common/urls.py +++ b/ishtar_common/urls.py @@ -98,8 +98,12 @@ urlpatterns += patterns('ishtar_common.views', name='get-person'), url(r'show-person(?:/(?P<pk>.+))?/(?P<type>.+)?$', 'show_person', name='show-person'), + url(r'department-by-state/(?P<state_id>.+)?$', 'department_by_state', + name='department-by-state'), url(r'autocomplete-town/?$', 'autocomplete_town', name='autocomplete-town'), + url(r'autocomplete-advanced-town/(?P<department_id>[0-9]+[ABab]?)?$', + 'autocomplete_advanced_town', name='autocomplete-advanced-town'), url(r'autocomplete-department/?$', 'autocomplete_department', name='autocomplete-department'), url(r'new-author/(?:(?P<parent_name>[^/]+)/)?(?:(?P<limits>[^/]+)/)?$', diff --git a/ishtar_common/views.py b/ishtar_common/views.py index a8ab91fb9..66b488254 100644 --- a/ishtar_common/views.py +++ b/ishtar_common/views.py @@ -202,6 +202,45 @@ def autocomplete_town(request): for town in towns]) return HttpResponse(data, mimetype='text/plain') +def autocomplete_advanced_town(request, department_id=None, state_id=None): + if not request.GET.get('term'): + return HttpResponse(mimetype='text/plain') + q = request.GET.get('term') + q = unicodedata.normalize("NFKD", q).encode('ascii','ignore') + query = Q() + for q in q.split(' '): + extra = Q(name__icontains=q) + if settings.COUNTRY == 'fr': + extra = extra | Q(numero_insee__istartswith=q) + if not department_id: + extra = extra | Q(departement__label__istartswith=q) + query = query & extra + if department_id: + query = query & Q(departement__number__iexact=department_id) + if state_id: + query = query & Q(departement__state__number__iexact=state_id) + limit = 20 + towns = models.Town.objects.filter(query)[:limit] + result = [] + for town in towns: + val = town.name + if hasattr(town, 'numero_insee'): + val += " (%s)" % town.numero_insee + result.append({'id':town.pk, 'value':val}) + data = json.dumps(result) + return HttpResponse(data, mimetype='text/plain') + +def department_by_state(request, state_id=''): + if not state_id: + data = [] + else: + departments = models.Department.objects.filter(state__number=state_id) + data = json.dumps([{'id':department.pk, 'number':department.number, + 'value':unicode(department)} + for department in departments]) + return HttpResponse(data, mimetype='text/plain') + + from types import NoneType def format_val(val): diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py index 91594edbd..ba7e61e46 100644 --- a/ishtar_common/widgets.py +++ b/ishtar_common/widgets.py @@ -34,7 +34,7 @@ from django.utils.safestring import mark_safe from django.utils.simplejson import JSONEncoder from django.utils.translation import ugettext_lazy as _ -import models +from ishtar_common import models reverse_lazy = lazy(reverse, unicode) @@ -283,6 +283,105 @@ class JQueryAutoComplete(forms.TextInput): } return html +class JQueryTown(forms.TextInput): + """ + Town fields whith state and department pre-selections + """ + + def __init__(self, source, options={}, + attrs={}, new=False, limit={}): + self.options = None + self.attrs = {} + self.source = source + if len(options) > 0: + self.options = JSONEncoder().encode(options) + self.attrs.update(attrs) + self.new = new + self.limit = limit + + @classmethod + def encode_source(cls, source): + encoded_src = '' + if isinstance(source, list): + encoded_src = JSONEncoder().encode(source) + elif isinstance(source, str) \ + or isinstance(source, unicode): + src = escape(source) + if not src.endswith('/'): + src += "/" + encoded_src = "'%s'" % src + else: + try: + src = unicode(source) + if not src.endswith('/'): + src += "/" + encoded_src = "'%s'" % src + except: + raise ValueError('source type is not valid') + return encoded_src + + def render(self, name, value=None, attrs=None): + attrs_hidden = self.build_attrs(attrs, name=name) + attrs_select = self.build_attrs(attrs) + attrs_select['placeholder'] = _(u"Search...") + selected = '' + selected_state = '' + selected_department = '' + if value: + hiddens = [] + selects = [] + if type(value) not in (list, tuple): + values = unicode(escape(smart_unicode(value))) + values = values.replace('[', '').replace(']', '') + values = values.split(',') + else: + values = [] + for v in value: + values += v.split(',') + for v in values: + if not v: + continue + hiddens.append(v) + selects.append(v) + try: + item = models.Town.objects.get(pk=v) + selects[-1] = unicode(item) + if item.departement: + selected_department = item.departement.number + if item.departement.state: + selected_state = item.departement.state.number + selected = item.pk + except (models.Town.DoesNotExist, ValueError): + selects.pop() + hiddens.pop() + if hiddens and selects: + attrs_hidden['value'] = hiddens[0] + attrs_select['value'] = selects[0] + if not self.attrs.has_key('id'): + attrs_hidden['id'] = 'id_%s' % name + attrs_select['id'] = 'id_select_%s' % name + if 'class' not in attrs_select: + attrs_select['class'] = 'autocomplete' + + source = self.encode_source(self.source) + dct = {'source':mark_safe(source), + 'selected':selected, + 'safe_field_id':slugify(name).replace('-', '_'), + 'field_id':name} + if self.options: + dct['options'] = mark_safe('%s' % self.options) + + dct.update({'attrs_select':mark_safe(flatatt(attrs_select)), + 'attrs_hidden':mark_safe(flatatt(attrs_hidden)), + 'name':name, + 'states':models.State.objects.all().order_by('label'), + 'selected_department':selected_department, + 'selected_state':selected_state + }) + html = loader.get_template('blocks/JQueryAdvancedTown.html').render( + Context(dct)) + return html + class JQueryPersonOrganization(forms.TextInput): """ Complex widget which manage: diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py index 190a7fc86..2ad3635d7 100644 --- a/ishtar_common/wizards.py +++ b/ishtar_common/wizards.py @@ -95,8 +95,11 @@ class Wizard(NamedUrlWizardView): def get_template_names(self): templates = ['ishtar/wizard/default_wizard.html'] current_step = self.steps.current - if current_step in self.wizard_templates: - templates = [self.wizard_templates[current_step]] + templates + wizard_templates = dict([ + (key % {'url_name':self.url_name}, self.wizard_templates[key]) + for key in self.wizard_templates]) + if current_step in wizard_templates: + templates = [wizard_templates[current_step]] + templates elif current_step == self.steps.last: templates = ['ishtar/wizard/confirm_wizard.html'] + templates return templates |