diff options
author | Étienne Loks <etienne.loks@peacefrogs.net> | 2012-10-18 17:49:57 +0200 |
---|---|---|
committer | Étienne Loks <etienne.loks@peacefrogs.net> | 2012-10-18 17:51:30 +0200 |
commit | ade7bd4b74d9ae42c54648cc7390d8c067b5c5e3 (patch) | |
tree | 4136673563f802d6de992512e3c4adde86ef2a4e /ishtar_common | |
parent | 9a3d3dcbca9395c00e55d6ee4909ba9b9a4752f8 (diff) | |
download | Ishtar-ade7bd4b74d9ae42c54648cc7390d8c067b5c5e3.tar.bz2 Ishtar-ade7bd4b74d9ae42c54648cc7390d8c067b5c5e3.zip |
Djangoization - Major refactoring (step 1)
Diffstat (limited to 'ishtar_common')
116 files changed, 20149 insertions, 0 deletions
diff --git a/ishtar_common/__init__.py b/ishtar_common/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ishtar_common/__init__.py diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py new file mode 100644 index 000000000..6d22fbcfa --- /dev/null +++ b/ishtar_common/admin.py @@ -0,0 +1,240 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Admin description +""" + +from django import forms +from django.conf import settings +from django.contrib import admin +from django.core.exceptions import ObjectDoesNotExist +from django.utils.translation import ugettext_lazy as _ + +import models + +class HistorizedObjectAdmin(admin.ModelAdmin): + readonly_fields = ('history_modifier',) + def save_model(self, request, obj, form, change): + obj.history_modifier = request.user + obj.save() + +class DepartementAdmin(admin.ModelAdmin): + list_display = ('number', 'label',) + model = models.Departement + +admin.site.register(models.Departement, DepartementAdmin) + +class OrganizationAdmin(HistorizedObjectAdmin): + list_display = ('name', 'organization_type') + list_filter = ("organization_type",) + search_fields = ('name',) + model = models.Organization + +admin.site.register(models.Organization, OrganizationAdmin) + +class PersonAdmin(HistorizedObjectAdmin): + list_display = ('name', 'surname', 'email', 'person_type') + list_filter = ("person_type",) + search_fields = ('name', 'surname', 'email',) + model = models.Person + +admin.site.register(models.Person, PersonAdmin) + +class FileAdmin(HistorizedObjectAdmin): + list_display = ['year', 'numeric_reference', 'internal_reference', + 'end_date', 'file_type', 'general_contractor',] + if settings.COUNTRY == 'fr': + list_display += ['saisine_type', 'reference_number'] + list_filter = ("file_type", "year",) + search_fields = ('towns__name',) + model = models.File + +admin.site.register(models.File, FileAdmin) + +class OperationAdmin(HistorizedObjectAdmin): + list_display = ['year', 'operation_code', 'start_date', + 'excavation_end_date', 'end_date', + 'operation_type'] + list_filter = ("year", "operation_type",) + search_fields = ['towns__name', 'operation_code'] + if settings.COUNTRY == 'fr': + list_display += ['code_patriarche'] + search_fields += ['code_patriarche'] + model = models.Operation + +admin.site.register(models.Operation, OperationAdmin) + +class OperationSourceAdmin(admin.ModelAdmin): + list_display = ('operation', 'title', 'source_type',) + list_filter = ('source_type',) + search_fields = ('title', 'operation__name') + model = models.OperationSource + +admin.site.register(models.OperationSource, OperationSourceAdmin) + +class ParcelAdmin(HistorizedObjectAdmin): + list_display = ('section', 'parcel_number', 'operation', 'associated_file') + search_fields = ('operation__name',) + model = models.Parcel + +admin.site.register(models.Parcel, ParcelAdmin) + +class PeriodAdmin(admin.ModelAdmin): + list_display = ('label', 'start_date', 'end_date', 'parent') + model = models.Period + +admin.site.register(models.Period, PeriodAdmin) + +class DatingAdmin(admin.ModelAdmin): + list_display = ('period', 'start_date', 'end_date', 'dating_type', + 'quality') + list_filter = ("period", 'dating_type', 'quality') + model = models.Dating + +admin.site.register(models.Dating, DatingAdmin) + +class ContextRecordAdmin(HistorizedObjectAdmin): + list_display = ('label', 'length', 'width', + 'thickness', 'depth') + list_filter = ('has_furniture',) + search_fields = ('parcel__operation__name', "datings__period__label") + model = models.ContextRecord + +admin.site.register(models.ContextRecord, ContextRecordAdmin) + +class ContextRecordSourceAdmin(admin.ModelAdmin): + list_display = ('context_record', 'title', 'source_type',) + list_filter = ('source_type',) + search_fields = ('title', ) + model = models.ContextRecordSource + +admin.site.register(models.ContextRecordSource, ContextRecordSourceAdmin) + +class BaseItemAdmin(HistorizedObjectAdmin): + list_display = ('label', 'context_record', 'is_isolated') + search_fields = ('label', 'context_record__parcel__operation__name',) + model = models.BaseItem + +admin.site.register(models.BaseItem, BaseItemAdmin) + +class ItemAdmin(HistorizedObjectAdmin): + list_display = ('label', 'material_type', 'dating', 'volume', 'weight', + 'item_number',) + list_filter = ('material_type',) + search_fields = ('label', "dating__period__label") + model = models.Item + +admin.site.register(models.Item, ItemAdmin) + +class ItemSourceAdmin(admin.ModelAdmin): + list_display = ('item', 'title', 'source_type',) + list_filter = ('source_type',) + search_fields = ('title', ) + model = models.ItemSource + +admin.site.register(models.ItemSource, ItemSourceAdmin) + +class WarehouseAdmin(HistorizedObjectAdmin): + list_display = ('name', 'warehouse_type', 'town') + list_filter = ('warehouse_type',) + search_fields = ('name', 'town') + model = models.Warehouse + +admin.site.register(models.Warehouse, WarehouseAdmin) + +class AdministrativeActAdmin(HistorizedObjectAdmin): + list_display = ('operation', 'act_type', 'signature_date') + list_filter = ('act_type',) + search_fields = ('operation__name',) + model = models.AdministrativeAct + +admin.site.register(models.AdministrativeAct, AdministrativeActAdmin) + +class ContainerTypeAdmin(admin.ModelAdmin): + list_display = ('label', 'reference', 'length', 'width', 'height', + 'volume') + model = models.ContainerType + +admin.site.register(models.ContainerType, ContainerTypeAdmin) + +class ContainerAdmin(admin.ModelAdmin): + list_display = ('reference', 'location', 'container_type',) + list_filter = ("container_type",) + model = models.Container + +admin.site.register(models.Container, ContainerAdmin) + +class TownAdmin(admin.ModelAdmin): + list_display = ['name',] + search_fields = ['name'] + if settings.COUNTRY == 'fr': + list_display += ['numero_insee', 'departement', ] + search_fields += ['numero_insee', 'departement__label', ] + list_filter = ("departement",) + model = models.Town + +admin.site.register(models.Town, TownAdmin) + +class AuthorAdmin(admin.ModelAdmin): + list_display = ['person', 'author_type'] + list_filter = ("author_type",) + model = models.Author + +admin.site.register(models.Author, AuthorAdmin) + +class PropertyAdmin(admin.ModelAdmin): + list_display = ['item', 'person', 'start_date', 'end_date'] + search_fields = ('item__label', 'person__name') + model = models.Property + +admin.site.register(models.Property, PropertyAdmin) + +class TreatmentAdmin(HistorizedObjectAdmin): + list_display = ('location', 'treatment_type', 'container', 'person') + list_filter = ('treatment_type',) + model = models.Treatment + +admin.site.register(models.Treatment, TreatmentAdmin) + +class TreatmentSourceAdmin(admin.ModelAdmin): + list_display = ('treatment', 'title', 'source_type',) + list_filter = ('source_type',) + search_fields = ('title',) + model = models.TreatmentSource + +admin.site.register(models.TreatmentSource, TreatmentSourceAdmin) + +class PersonTypeAdmin(admin.ModelAdmin): + model = models.PersonType + filter_vertical = ('rights',) + +admin.site.register(models.PersonType, PersonTypeAdmin) + +basic_models = [models.IshtarUser, models.FileType, models.OperationType, + models.DatingType, models.DatingQuality, models.SourceType, + models.MaterialType, models.ParcelOwner, models.WarehouseType, + models.ActType, models.AuthorType, models.OrganizationType, + models.TreatmentType, models.RemainType, models.PermitType, + models.Unit, models.ActivityType, models.IdentificationType] +if settings.COUNTRY == 'fr': + basic_models += [models.Arrondissement, models.Canton, models.SaisineType] + +for model in basic_models: + admin.site.register(model) diff --git a/ishtar_common/backend.py b/ishtar_common/backend.py new file mode 100644 index 000000000..f50edd708 --- /dev/null +++ b/ishtar_common/backend.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Permission backend to manage "own" objects +""" + +from django.conf import settings +from django.contrib.auth.models import User +from django.core.exceptions import ObjectDoesNotExist + +import models + +class ObjectOwnPermBackend(object): + supports_object_permissions = True + supports_anonymous_user = True + + def authenticate(self, username, password): + # managed by the default backend + return None + + def has_perm(self, user_obj, perm, model=None, obj=None): + if not user_obj.is_authenticated(): + return False + if not model: + # let it manage by the default backend + return False + try: + ishtar_user = models.IshtarUser.objects.get(user_ptr=user_obj) + except ObjectDoesNotExist: + return False + try: + # only manage "own" permissions + assert perm.split('.')[-1].split('_')[1] == 'own' + except (IndexError, AssertionError): + return False + if ishtar_user.person.person_type \ + == models.PersonType.objects.get(txt_idx="administrator"): + return True + if obj is None: + model_name = perm.split('_')[-1].capitalize() + if not hasattr(models, model_name): + return False + model = getattr(models, model_name) + return user_obj.has_perm(perm) and model.has_item_of(ishtar_user) + return user_obj.has_perm(perm) and obj.is_own(user_obj) diff --git a/ishtar_common/context_processors.py b/ishtar_common/context_processors.py new file mode 100644 index 000000000..5de5a6afd --- /dev/null +++ b/ishtar_common/context_processors.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +from django.conf import settings +from django.contrib.sites.models import Site +from django.utils.translation import ugettext, ugettext_lazy as _ + +from menus import Menu +import models + +def get_base_context(request): + dct = {'URL_PATH':settings.URL_PATH} + dct["APP_NAME"] = Site.objects.get_current().name + dct["COUNTRY"] = settings.COUNTRY + if 'MENU' not in request.session or \ + request.session['MENU'].user != request.user: + menu = Menu(request.user) + menu.init() + request.session['MENU'] = menu + if 'CURRENT_ACTION' in request.session: + dct['CURRENT_ACTION'] = request.session['CURRENT_ACTION'] + dct['MENU'] = request.session['MENU'] + dct['JQUERY_URL'] = settings.JQUERY_URL + dct['JQUERY_UI_URL'] = settings.JQUERY_UI_URL + dct['current_menu'] = [] + for lbl, model in ((_(u"Archaeological file"), models.File), + (_(u"Operation"), models.Operation), + (_(u"Context record"), models.ContextRecord), + (_(u"Archaeological item"), models.Item), + ): + model_name = model.__name__.lower() + current = model_name in request.session and request.session[model_name] + items = [] + for item in model.get_owns(request.user): + items.append((item.pk, unicode(item), unicode(item.pk) == current)) + if items: + dct['current_menu'].append((lbl, model_name, items)) + return dct + diff --git a/ishtar_common/fixtures/initial_data.json b/ishtar_common/fixtures/initial_data.json new file mode 100644 index 000000000..c4d235a3c --- /dev/null +++ b/ishtar_common/fixtures/initial_data.json @@ -0,0 +1,1863 @@ +[ + { + "pk": 1, + "model": "ishtar_common.organizationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "sra", + "label": "Service R\u00e9gional d'Arch\u00e9ologie" + } + }, + { + "pk": 2, + "model": "ishtar_common.organizationtype", + "fields": { + "comment": "D\u00e9cret 2004\r\n\r\n\"Op\u00e9rateurs\" les personnes qui r\u00e9alisent les op\u00e9rations arch\u00e9ologiques.", + "available": true, + "txt_idx": "operator", + "label": "Op\u00e9rateur d'arch\u00e9ologie pr\u00e9ventive" + } + }, + { + "pk": 4, + "model": "ishtar_common.organizationtype", + "fields": { + "comment": "Laboratoire ayant sous sa responsabilit\u00e9 du mobilier arch\u00e9ologique de mani\u00e8re temporaire. C'est un type de d\u00e9p\u00f4t. C'est un lieu de traitement.", + "available": true, + "txt_idx": "restoration_laboratory", + "label": "Laboratoire de restauration" + } + }, + { + "pk": 5, + "model": "ishtar_common.organizationtype", + "fields": { + "comment": "Pour des entreprises, collectivit\u00e9s territoriales ou autres organisations", + "available": true, + "txt_idx": "general_contractor", + "label": "Am\u00e9nageur" + } + }, + { + "pk": 7, + "model": "ishtar_common.organizationtype", + "fields": { + "comment": "Cette organisation et ses membres travaillent b\u00e9n\u00e9volement", + "available": true, + "txt_idx": "volunteer", + "label": "B\u00e9n\u00e9vole" + } + }, + { + "pk": 8, + "model": "ishtar_common.organizationtype", + "fields": { + "comment": "les services qui d\u00e9livrent les autorisations requises pour les diff\u00e9rents projets (DDE, services\r\nurbanisme des collectivit\u00e9s, pr\u00e9fectures, Drire, etc.)", + "available": true, + "txt_idx": "planning_service", + "label": "Service instructeur" + } + }, + { + "pk": 9, + "model": "ishtar_common.organizationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "museum", + "label": "Mus\u00e9e" + } + }, + { + "pk": 6, + "model": "ishtar_common.organizationtype", + "fields": { + "comment": "Laboratoire de recherche du CNRS. Peut-\u00eatre une UMR et donc int\u00e9gr\u00e9 des chercheurs de l'universit\u00e9. n'inclus pas les \"laboratoires\" priv\u00e9s", + "available": true, + "txt_idx": "research_laboratory", + "label": "Laboratoire de recherche" + } + }, + { + "pk": 1, + "model": "ishtar_common.persontype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "administrator", + "label": "Administrateur" + } + }, + { + "pk": 2, + "model": "ishtar_common.persontype", + "fields": { + "comment": "Article 13 D\u00e9cret 2004\r\n\r\nLe pr\u00e9fet de r\u00e9gion \u00e9dicte les prescriptions arch\u00e9ologiques, d\u00e9livre l'autorisation de fouille et d\u00e9signe le responsable scientifique de toute op\u00e9ration d'arch\u00e9ologie pr\u00e9ventive.\r\n\r\nLe responsable scientifique est l'interlocuteur du pr\u00e9fet de r\u00e9gion et le garant de la qualit\u00e9 scientifique de l'op\u00e9ration arch\u00e9ologique. A ce titre, il prend, dans le cadre de la mise en oeuvre du projet d'intervention de l'op\u00e9rateur, les d\u00e9cisions relatives \u00e0 la conduite scientifique de l'op\u00e9ration et \u00e0 l'\u00e9laboration du rapport dont il dirige la r\u00e9daction. Il peut \u00eatre diff\u00e9rent pour la r\u00e9alisation du diagnostic et pour la r\u00e9alisation de la fouille.", + "available": true, + "txt_idx": "head_scientist", + "label": "Responsable scientifique" + } + }, + { + "pk": 3, + "model": "ishtar_common.persontype", + "fields": { + "comment": "Responsables de dossiers d'arch\u00e9ologie", + "available": true, + "txt_idx": "sra_agent", + "label": "Agent scientifique SRA" + } + }, + { + "pk": 4, + "model": "ishtar_common.persontype", + "fields": { + "comment": "Acc\u00e8s pour les secr\u00e9taires d'un SRA", + "available": true, + "txt_idx": "secretarial_dept", + "label": "Secr\u00e9tariat SRA" + } + }, + { + "pk": 5, + "model": "ishtar_common.persontype", + "fields": { + "comment": "Cette personne peut g\u00e9rer du mobilier qu'il n'a pas cr\u00e9\u00e9\r\n\r\n", + "available": true, + "txt_idx": "warehouse_manager", + "label": "Gestionnaire de d\u00e9p\u00f4t" + } + }, + { + "pk": 6, + "model": "ishtar_common.persontype", + "fields": { + "comment": "Responsable de l'am\u00e9nagement", + "available": true, + "txt_idx": "general_contractor", + "label": "Am\u00e9nageur" + } + }, + { + "pk": 7, + "model": "ishtar_common.persontype", + "fields": { + "comment": "Un acc\u00e8s limit\u00e9 \u00e0 la base, uniquement en lecture. Apr\u00e8s enregistrement.", + "available": true, + "txt_idx": "public_access", + "label": "Acc\u00e8s publique" + } + }, + { + "pk": 2, + "model": "ishtar_common.authortype", + "fields": { + "comment": "Il y a plusieurs \u00e0 une m\u00eame source. Au m\u00eame niveau de responsabilit\u00e9.", + "available": true, + "txt_idx": "co_author", + "label": "Co-auteur " + } + }, + { + "pk": 3, + "model": "ishtar_common.authortype", + "fields": { + "comment": "Cette personne est l'auteur principal de la source. Les autres auteurs sont des collaborateurs.", + "available": true, + "txt_idx": "main_author", + "label": "Auteur principal" + } + }, + { + "pk": 4, + "model": "ishtar_common.authortype", + "fields": { + "comment": "Cet auteur n'est pas l'auteur principal de la source mais un collaborateur. Il n'est pas auteur au m\u00eame niveau que l'auteur principal.", + "available": true, + "txt_idx": "associate_author", + "label": "Collaborateur" + } + }, + { + "pk": 1, + "model": "ishtar_common.sourcetype", + "fields": { + "comment": "Photographie argentique sous une forme imprim\u00e9e", + "available": true, + "txt_idx": "photo_print", + "label": "Epreuve de photographie argentique" + } + }, + { + "pk": 2, + "model": "ishtar_common.sourcetype", + "fields": { + "comment": "Rapport de fouille arch\u00e9ologique", + "available": true, + "txt_idx": "final_archaeological_report", + "label": "Rapport final d'op\u00e9ration (fouille)" + } + }, + { + "pk": 3, + "model": "ishtar_common.sourcetype", + "fields": { + "comment": "Rapport li\u00e9 \u00e0 une autorisation de sondage.", + "available": true, + "txt_idx": "survey_report", + "label": "Rapport de sondage" + } + }, + { + "pk": 4, + "model": "ishtar_common.sourcetype", + "fields": { + "comment": "Rapport li\u00e9 \u00e0 un arr\u00eat\u00e9 de prescription de diagnostic arch\u00e9ologique.", + "available": true, + "txt_idx": "diagnostic_report", + "label": "Rapport de diagnostic" + } + }, + { + "pk": 5, + "model": "ishtar_common.sourcetype", + "fields": { + "comment": "Source photographique num\u00e9rique", + "available": true, + "txt_idx": "digital_photo", + "label": "Photographie num\u00e9rique" + } + }, + { + "pk": 6, + "model": "ishtar_common.sourcetype", + "fields": { + "comment": "Rapport de laboratoire d'analyse", + "available": true, + "txt_idx": "lab_report", + "label": "Rapport d'analyse" + } + }, + { + "pk": 7, + "model": "ishtar_common.sourcetype", + "fields": { + "comment": "Rapport li\u00e9 \u00e0 la restauration ou la stabilisation d'un lot de mobilier ou d'un objet isol\u00e9", + "available": true, + "txt_idx": "restoration_report", + "label": "Rapport de restauration" + } + }, + { + "pk": 8, + "model": "ishtar_common.sourcetype", + "fields": { + "comment": "Rapport li\u00e9 \u00e0 une autorisation de prospection inventaire", + "available": true, + "txt_idx": "general_survey_report", + "label": "Rapport de prospection inventaire" + } + }, + { + "pk": 9, + "model": "ishtar_common.sourcetype", + "fields": { + "comment": "Rapport li\u00e9 \u00e0 une autorisation de prospection th\u00e9matique. Ce type de rapport passe d'ordinaire en CIRA.", + "available": true, + "txt_idx": "thematic_survey_report", + "label": "Rapport de prospection th\u00e9matique" + } + }, + { + "pk": 1, + "model": "ishtar_common.filetype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "preventive", + "label": "Arch\u00e9ologie pr\u00e9ventive" + } + }, + { + "pk": 2, + "model": "ishtar_common.filetype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "prog", + "label": "Arch\u00e9ologie programm\u00e9e" + } + }, + { + "pk": 1, + "model": "ishtar_common.permittype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "pc", + "label": "PC" + } + }, + { + "pk": 2, + "model": "ishtar_common.permittype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "pa", + "label": "PA" + } + }, + { + "pk": 3, + "model": "ishtar_common.permittype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "zac", + "label": "Dossier de r\u00e9alisation de ZAC" + } + }, + { + "pk": 4, + "model": "ishtar_common.permittype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "ei", + "label": "Etude d'impact" + } + }, + { + "pk": 5, + "model": "ishtar_common.permittype", + "fields": { + "comment": "Certificat d'urbanisme", + "available": true, + "txt_idx": "cu", + "label": "CU" + } + }, + { + "pk": 2, + "model": "ishtar_common.saisinetype", + "fields": { + "comment": " I. - Dans les cas mentionn\u00e9s aux 1\u00b0 \u00e0 5\u00b0 de l'article 4, le pr\u00e9fet de r\u00e9gion est saisi :\r\n\r\n1\u00b0 Pour les permis de construire, les permis d'am\u00e9nager et les permis de d\u00e9molir, par le pr\u00e9fet de d\u00e9partement qui lui adresse, d\u00e8s qu'il a re\u00e7u les \u00e9l\u00e9ments transmis par le maire en application des articles R. 423-7 \u00e0 R. 423-9 du code de l'urbanisme, les pi\u00e8ces pr\u00e9vues par le dernier alin\u00e9a de l'article R. 423-2, faisant notamment appara\u00eetre l'emplacement pr\u00e9vu des travaux sur le terrain d'assiette, leur superficie, leur impact sur le sous-sol ;\r\n\r\n2\u00b0 Pour les zones d'am\u00e9nagement concert\u00e9, par la personne publique ayant pris l'initiative de la cr\u00e9ation de la zone qui adresse au pr\u00e9fet de r\u00e9gion le dossier de r\u00e9alisation approuv\u00e9 pr\u00e9vu \u00e0 l'article R. 311-7 du code de l'urbanisme ;\r\n\r\n3\u00b0 Abrog\u00e9\r\n\r\n4\u00b0 Pour les am\u00e9nagements et ouvrages mentionn\u00e9s au 5\u00b0 de l'article 4 qui sont soumis \u00e0 une autorisation administrative autre qu'une autorisation d'urbanisme, par le service charg\u00e9 de recevoir la demande d'autorisation, qui adresse une copie du dossier de demande au pr\u00e9fet de r\u00e9gion ;\r\n\r\n5\u00b0 Pour les am\u00e9nagements et ouvrages mentionn\u00e9s au 5\u00b0 de l'article 4 qui ne sont pas soumis \u00e0 une autorisation administrative, par l'am\u00e9nageur. Celui-ci adresse au pr\u00e9fet de r\u00e9gion un dossier d\u00e9crivant les travaux projet\u00e9s, notamment leur emplacement pr\u00e9vu sur le terrain d'assiette, leur superficie, leur impact sur le sous-sol et indiquant la date \u00e0 laquelle ils ont \u00e9t\u00e9 arr\u00eat\u00e9s.\r\n\r\nII. - Pour les travaux sur des monuments historiques mentionn\u00e9s au 6\u00b0 de l'article 4, la saisine du pr\u00e9fet de r\u00e9gion au titre de l'autorisation exig\u00e9e par l'article L. 621-9 du code du patrimoine vaut saisine au titre du pr\u00e9sent d\u00e9cret.", + "available": true, + "txt_idx": "Article_8", + "delay": 21, + "label": "Article 8" + } + }, + { + "pk": 3, + "model": "ishtar_common.saisinetype", + "fields": { + "comment": " Les am\u00e9nageurs peuvent, avant de d\u00e9poser une demande pour obtenir les autorisations requises par les lois et r\u00e8glements ou avant d'engager toute autre proc\u00e9dure, saisir le pr\u00e9fet de r\u00e9gion afin qu'il examine si leur projet est susceptible de donner lieu \u00e0 des prescriptions arch\u00e9ologiques.\r\n\r\nA cette fin, ils produisent un dossier qui comporte un plan parcellaire et les r\u00e9f\u00e9rences cadastrales, le descriptif du projet et son emplacement sur le terrain d'assiette ainsi que, le cas \u00e9ch\u00e9ant, une notice pr\u00e9cisant les modalit\u00e9s techniques envisag\u00e9es pour l'ex\u00e9cution des travaux.\r\n\r\nSi le pr\u00e9fet de r\u00e9gion constate que le projet est susceptible d'affecter des \u00e9l\u00e9ments du patrimoine arch\u00e9ologique, il informe le demandeur, dans le d\u00e9lai de deux mois \u00e0 compter de la r\u00e9ception de la demande, que le projet qu'il lui a pr\u00e9sent\u00e9 donnera lieu \u00e0 des prescriptions de diagnostic arch\u00e9ologique.", + "available": true, + "txt_idx": "Article_10", + "delay": 60, + "label": "Article 10" + } + }, + { + "pk": 4, + "model": "ishtar_common.saisinetype", + "fields": { + "comment": " Si le pr\u00e9fet de r\u00e9gion a fait conna\u00eetre, en application de l'article 10, la n\u00e9cessit\u00e9 d'un diagnostic, l'am\u00e9nageur peut le saisir d'une demande anticip\u00e9e de prescription.\r\n\r\nLe pr\u00e9fet de r\u00e9gion prescrit alors, dans les conditions pr\u00e9vues par le pr\u00e9sent d\u00e9cret, la r\u00e9alisation d'un diagnostic arch\u00e9ologique et, si des \u00e9l\u00e9ments du patrimoine arch\u00e9ologique pr\u00e9sents sur le site sont d\u00e9j\u00e0 connus, prend les autres mesures pr\u00e9vues \u00e0 l'article 14.\r\n\r\nLa redevance d'arch\u00e9ologie pr\u00e9ventive correspondante est due par le demandeur, conform\u00e9ment au dernier alin\u00e9a de l'article L. 524-4 du code du patrimoine.", + "available": true, + "txt_idx": "Article_12", + "delay": 30, + "label": "Article 12" + } + }, + { + "pk": 5, + "model": "ishtar_common.saisinetype", + "fields": { + "comment": "Article 6\r\n\r\n Lorsqu'il dispose d'informations lui indiquant qu'un projet qui ne lui est pas transmis en application de l'arr\u00eat\u00e9 mentionn\u00e9 \u00e0 l'article 5 est n\u00e9anmoins susceptible d'affecter des \u00e9l\u00e9ments du patrimoine arch\u00e9ologique, le pr\u00e9fet de r\u00e9gion peut demander au maire de lui communiquer au cours de l'instruction, selon le cas, le dossier de demande de permis de construire, de permis d'am\u00e9nager, de permis de d\u00e9molir ou le dossier de r\u00e9alisation de zone d'am\u00e9nagement concert\u00e9 qui correspond \u00e0 ce projet.\r\n\r\nIl peut, pour le m\u00eame motif, demander au maire de lui communiquer le dossier d'une d\u00e9claration pr\u00e9alable d\u00e9pos\u00e9e en application de l'article L. 421-4 du code de l'urbanisme.", + "available": true, + "txt_idx": "Article_6", + "delay": 30, + "label": "Auto-saisine" + } + }, + { + "pk": 1, + "model": "ishtar_common.operationtype", + "fields": { + "comment": "Une op\u00e9ration arch\u00e9ologique visant \u00e0 qualifier et quantifier la pr\u00e9sence de vestiges sur une surface donn\u00e9e.", + "available": true, + "txt_idx": "arch_diagnostic", + "label": "Diagnostic arch\u00e9ologique" + } + }, + { + "pk": 2, + "model": "ishtar_common.operationtype", + "fields": { + "comment": "A pr\u00e9ciser", + "available": true, + "txt_idx": "prev_excavation", + "label": "Fouille arch\u00e9ologique pr\u00e9ventive" + } + }, + { + "pk": 3, + "model": "ishtar_common.operationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "prog_excavation", + "label": "Fouille programm\u00e9e" + } + }, + { + "pk": 4, + "model": "ishtar_common.operationtype", + "fields": { + "comment": "Pas assez gros pour \u00eatre une fouille, mais porte n\u00e9anmoins atteinte au sous-sol.", + "available": true, + "txt_idx": "Sampling", + "label": "Sondage" + } + }, + { + "pk": 5, + "model": "ishtar_common.operationtype", + "fields": { + "comment": "Une campagne de prospection sur un th\u00e8me particulier", + "available": true, + "txt_idx": "thematic_survey", + "label": "Prospection th\u00e9matique" + } + }, + { + "pk": 6, + "model": "ishtar_common.operationtype", + "fields": { + "comment": "Prospection visant \u00e0 d\u00e9tecter tout type de vestiges (ou presque) sur une surface donn\u00e9e. ", + "available": true, + "txt_idx": "inventory_survey", + "label": "Prospection inventaire" + } + }, + { + "pk": 1, + "model": "ishtar_common.remaintype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "villa", + "label": "villa" + } + }, + { + "pk": 2, + "model": "ishtar_common.remaintype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "enclosure", + "label": "enclos" + } + }, + { + "pk": 3, + "model": "ishtar_common.remaintype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "church", + "label": "\u00e9glise" + } + }, + { + "pk": 4, + "model": "ishtar_common.remaintype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "pit", + "label": "fosse" + } + }, + { + "pk": 5, + "model": "ishtar_common.remaintype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "cairn", + "label": "cairn" + } + }, + { + "pk": 6, + "model": "ishtar_common.remaintype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "ditch", + "label": "foss\u00e9" + } + }, + { + "pk": 7, + "model": "ishtar_common.remaintype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "post_hole", + "label": "trous de poteaux" + } + }, + { + "pk": 1, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": null, + "end_date": -10000, + "order": 2000, + "label": "Pal\u00e9olithique", + "start_date": -450000, + "txt_idx": "paleolithic" + } + }, + { + "pk": 2, + "model": "ishtar_common.period", + "fields": { + "comment": "1100, 'Pal\u00e9olithique ancien', , )", + "available": true, + "parent": 1, + "end_date": -150000, + "order": 1100, + "label": "Pal\u00e9olithique ancien", + "start_date": -450000, + "txt_idx": "ancien_paleolithic" + } + }, + { + "pk": 3, + "model": "ishtar_common.period", + "fields": { + "comment": "1200, '', , ),", + "available": true, + "parent": 1, + "end_date": -35000, + "order": 1200, + "label": "Pal\u00e9olithique moyen", + "start_date": -150000, + "txt_idx": "middle_paleolithic" + } + }, + { + "pk": 4, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 1, + "end_date": -12000, + "order": 1300, + "label": "Pal\u00e9olithique sup\u00e9rieur", + "start_date": -35000, + "txt_idx": "late_paleolithic" + } + }, + { + "pk": 5, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 1, + "end_date": -10000, + "order": 1400, + "label": "Pal\u00e9olithique sup\u00e9rieur final", + "start_date": -12000, + "txt_idx": "final_paleolithic" + } + }, + { + "pk": 6, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": null, + "end_date": -5000, + "order": 3000, + "label": "M\u00e9solithique", + "start_date": -10000, + "txt_idx": "mesolithic" + } + }, + { + "pk": 7, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 6, + "end_date": -7000, + "order": 2100, + "label": "M\u00e9solithique ancien", + "start_date": -10000, + "txt_idx": "old_mesolithic" + } + }, + { + "pk": 8, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": false, + "parent": 6, + "end_date": 0, + "order": 2200, + "label": "M\u00e9solithique moyen", + "start_date": 0, + "txt_idx": "middle_mesolithic" + } + }, + { + "pk": 9, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 6, + "end_date": -5000, + "order": 2300, + "label": "M\u00e9solithique r\u00e9cent", + "start_date": -7000, + "txt_idx": "recent_mesolithic" + } + }, + { + "pk": 10, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": null, + "end_date": -2000, + "order": 4000, + "label": "N\u00e9olithique", + "start_date": -5500, + "txt_idx": "neolithic" + } + }, + { + "pk": 11, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 10, + "end_date": -4500, + "order": 3100, + "label": "N\u00e9olithique ancien", + "start_date": -5500, + "txt_idx": "old_neolithic" + } + }, + { + "pk": 12, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 10, + "end_date": -300, + "order": 3200, + "label": "N\u00e9olithique moyen", + "start_date": -4500, + "txt_idx": "middle_neolithic" + } + }, + { + "pk": 13, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 10, + "end_date": -2500, + "order": 3300, + "label": "N\u00e9olithique r\u00e9cent", + "start_date": -3200, + "txt_idx": "recent_neolithic" + } + }, + { + "pk": 14, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 10, + "end_date": -2000, + "order": 3400, + "label": "N\u00e9olithique final", + "start_date": -2800, + "txt_idx": "final_neolithic" + } + }, + { + "pk": 15, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": null, + "end_date": -40, + "order": 5000, + "label": "Protohistoire", + "start_date": -2000, + "txt_idx": "protohistory" + } + }, + { + "pk": 16, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 15, + "end_date": -750, + "order": 4100, + "label": "\u00c2ge du Bronze", + "start_date": -2000, + "txt_idx": "bronze_age" + } + }, + { + "pk": 17, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 15, + "end_date": -40, + "order": 4200, + "label": "\u00c2ge du Fer", + "start_date": -800, + "txt_idx": "iron_age" + } + }, + { + "pk": 18, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 16, + "end_date": -1600, + "order": 4110, + "label": "\u00c2ge du Bronze ancien", + "start_date": -2000, + "txt_idx": "old_bronze_age" + } + }, + { + "pk": 19, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 16, + "end_date": -1200, + "order": 4120, + "label": "\u00c2ge du Bronze moyen", + "start_date": -1600, + "txt_idx": "middle_bronze_age" + } + }, + { + "pk": 20, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 16, + "end_date": -750, + "order": 4130, + "label": "\u00c2ge du Bronze final", + "start_date": -1200, + "txt_idx": "final_bronze_age" + } + }, + { + "pk": 21, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 17, + "end_date": -450, + "order": 4210, + "label": "Premier \u00c2ge du Fer", + "start_date": -800, + "txt_idx": "first_iron_age" + } + }, + { + "pk": 22, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 17, + "end_date": -40, + "order": 4220, + "label": "Deuxi\u00e8me \u00c2ge du Fer", + "start_date": -500, + "txt_idx": "second_iron_age" + } + }, + { + "pk": 23, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": null, + "end_date": 476, + "order": 6000, + "label": "Gallo-romain", + "start_date": -40, + "txt_idx": "gallo-roman" + } + }, + { + "pk": 24, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 23, + "end_date": -27, + "order": 5100, + "label": "R\u00e9publique", + "start_date": -40, + "txt_idx": "republic" + } + }, + { + "pk": 25, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 23, + "end_date": 192, + "order": 5200, + "label": "Haut-empire", + "start_date": -27, + "txt_idx": "high-empire" + } + }, + { + "pk": 26, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 23, + "end_date": 476, + "order": 5300, + "label": "Bas-empire", + "start_date": 192, + "txt_idx": "low_empire" + } + }, + { + "pk": 27, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": null, + "end_date": 1492, + "order": 7000, + "label": "Moyen-\u00e2ge", + "start_date": 476, + "txt_idx": "middle_age" + } + }, + { + "pk": 28, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 27, + "end_date": 987, + "order": 6100, + "label": "Haut moyen-\u00e2ge", + "start_date": 476, + "txt_idx": "476" + } + }, + { + "pk": 29, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 27, + "end_date": 1204, + "order": 6200, + "label": "Moyen-\u00e2ge classique", + "start_date": 987, + "txt_idx": "classic_middle_age" + } + }, + { + "pk": 30, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 27, + "end_date": 1492, + "order": 6300, + "label": "Bas moyen-\u00e2ge", + "start_date": 1204, + "txt_idx": "low_middle_age" + } + }, + { + "pk": 31, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": null, + "end_date": 2011, + "order": 8000, + "label": "P\u00e9riode r\u00e9cente", + "start_date": 1492, + "txt_idx": "recent_times" + } + }, + { + "pk": 32, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 31, + "end_date": 1815, + "order": 7100, + "label": "Epoque moderne", + "start_date": 1492, + "txt_idx": "modern" + } + }, + { + "pk": 33, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": 31, + "end_date": 2011, + "order": 7200, + "label": "Epoque contemporaine", + "start_date": 1815, + "txt_idx": "contemporan" + } + }, + { + "pk": 34, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": null, + "end_date": 0, + "order": 0, + "label": "Epoque ind\u00e9termin\u00e9e", + "start_date": 0, + "txt_idx": "indetermined" + } + }, + { + "pk": 35, + "model": "ishtar_common.period", + "fields": { + "comment": "", + "available": true, + "parent": null, + "end_date": 0, + "order": 10000, + "label": "Non-renseign\u00e9", + "start_date": 0, + "txt_idx": "not_yet_documented" + } + }, + { + "pk": 2, + "model": "ishtar_common.datingtype", + "fields": { + "comment": "Une \u00e9tude du mobilier est la source de datation", + "available": true, + "txt_idx": "from_artefact", + "label": "D'apr\u00e8s \u00e9tude du mobilier" + } + }, + { + "pk": 1, + "model": "ishtar_common.datingtype", + "fields": { + "comment": "D'apr\u00e8s une datation de type C14, OSL, TL, arch\u00e9omagn\u00e9tisme, etc, forunissant une date en BPcal avec une marge.", + "available": true, + "txt_idx": "from_absolute_dating", + "label": "D'apr\u00e8s datation absolue" + } + }, + { + "pk": 2, + "model": "ishtar_common.datingquality", + "fields": { + "comment": "datation a v\u00e9rifier", + "available": true, + "txt_idx": "estimated", + "label": "Estim\u00e9e " + } + }, + { + "pk": 1, + "model": "ishtar_common.datingquality", + "fields": { + "comment": "Datation fond\u00e9e sur des faits", + "available": true, + "txt_idx": "sure", + "label": "Aver\u00e9e" + } + }, + { + "pk": 1, + "model": "ishtar_common.unit", + "fields": { + "comment": "Cette unit\u00e9 n'a pas de volume", + "available": true, + "parent": null, + "label": "N\u00e9gative", + "order": 100, + "txt_idx": "negative" + } + }, + { + "pk": 2, + "model": "ishtar_common.unit", + "fields": { + "comment": "", + "available": true, + "parent": 1, + "label": "Creusement", + "order": 110, + "txt_idx": "digging" + } + }, + { + "pk": 3, + "model": "ishtar_common.unit", + "fields": { + "comment": "", + "available": true, + "parent": 1, + "label": "D\u00e9rasement", + "order": 120, + "txt_idx": "partial_destruction" + } + }, + { + "pk": 4, + "model": "ishtar_common.unit", + "fields": { + "comment": "", + "available": true, + "parent": null, + "label": "Couche", + "order": 200, + "txt_idx": "layer" + } + }, + { + "pk": 5, + "model": "ishtar_common.unit", + "fields": { + "comment": "", + "available": true, + "parent": 4, + "label": "Couche construite", + "order": 210, + "txt_idx": "builded_layer" + } + }, + { + "pk": 6, + "model": "ishtar_common.unit", + "fields": { + "comment": "", + "available": true, + "parent": 4, + "label": "Remblai", + "order": 220, + "txt_idx": "embankment" + } + }, + { + "pk": 7, + "model": "ishtar_common.unit", + "fields": { + "comment": "", + "available": true, + "parent": null, + "label": "Alt\u00e9ration", + "order": 300, + "txt_idx": "alteration" + } + }, + { + "pk": 8, + "model": "ishtar_common.unit", + "fields": { + "comment": "", + "available": true, + "parent": 7, + "label": "Impact thermique", + "order": 310, + "txt_idx": "thermal_impact" + } + }, + { + "pk": 9, + "model": "ishtar_common.unit", + "fields": { + "comment": "Unit\u00e9 g\u00e9n\u00e9rale (d'ordinaire virtuelle) pouvant regrouper du mobilier trouver en dehors d'un contexte spatialis\u00e9 : mobilier trouver lors d'un d\u00e9capage, sous une semelle d'un fouilleur, dans les d\u00e9blais, etc.", + "available": true, + "parent": null, + "label": "Hors contexte", + "order": 1, + "txt_idx": "not_in_context" + } + }, + { + "pk": 10, + "model": "ishtar_common.unit", + "fields": { + "comment": "Unit\u00e9 repr\u00e9sentant une partie d'un niveau d\u00e9coup\u00e9 en carr\u00e9s r\u00e9f\u00e9renc\u00e9s.", + "available": true, + "parent": null, + "label": "Carr\u00e9", + "order": 10, + "txt_idx": "square" + } + }, + { + "pk": 1, + "model": "ishtar_common.activitytype", + "fields": { + "comment": "Unit\u00e9 enregistrement qui n'est pas directement d'origine anthropique. ", + "available": true, + "txt_idx": "natural", + "order": 1000, + "label": "Naturelle" + } + }, + { + "pk": 2, + "model": "ishtar_common.activitytype", + "fields": { + "comment": "Unit\u00e9 \u00e9labor\u00e9e par l'homme, comme une mur ou un sol am\u00e9nag\u00e9 par exemple", + "available": true, + "txt_idx": "construction", + "order": 1100, + "label": "Construction" + } + }, + { + "pk": 3, + "model": "ishtar_common.activitytype", + "fields": { + "comment": "Unit\u00e9 r\u00e9sultant de l'arr\u00eat d'anthropisation", + "available": true, + "txt_idx": "desertion", + "order": 1200, + "label": "Abandon" + } + }, + { + "pk": 4, + "model": "ishtar_common.activitytype", + "fields": { + "comment": "Unit\u00e9 li\u00e9e \u00e0 l'anthropisation elle-m\u00eame", + "available": true, + "txt_idx": "occupation", + "order": 1300, + "label": "Occupation" + } + }, + { + "pk": 1, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "Niveau cultiv\u00e9 ou non, actuel.", + "available": true, + "txt_idx": "soil", + "order": 1000, + "label": "Terre v\u00e9g\u00e9tale" + } + }, + { + "pk": 2, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "masonry", + "order": 1100, + "label": "Ma\u00e7onnerie" + } + }, + { + "pk": 3, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "wall", + "order": 1200, + "label": "Mur" + } + }, + { + "pk": 4, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "occupation_level", + "order": 1300, + "label": "Niveau d'occupation" + } + }, + { + "pk": 5, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "desertion_level", + "order": 1400, + "label": "Niveau d'abandon" + } + }, + { + "pk": 6, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "geological_level", + "order": 1400, + "label": "Niveau g\u00e9ologique" + } + }, + { + "pk": 7, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "embankment", + "order": 1500, + "label": "Remblai" + } + }, + { + "pk": 8, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "archaeological_soil", + "order": 1600, + "label": "Sol arch\u00e9ologique" + } + }, + { + "pk": 9, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "foundation_level", + "order": 1700, + "label": "Radier" + } + }, + { + "pk": 10, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "digging", + "order": 1800, + "label": "Creusement" + } + }, + { + "pk": 11, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "colluvial_unit", + "order": 1800, + "label": "Colluvions" + } + }, + { + "pk": 12, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "windthrow", + "order": 1900, + "label": "Chablis" + } + }, + { + "pk": 13, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "filling", + "order": 2000, + "label": "Comblement" + } + }, + { + "pk": 14, + "model": "ishtar_common.identificationtype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "unknown", + "order": 100, + "label": "Ind\u00e9termin\u00e9" + } + }, + { + "pk": 1, + "model": "ishtar_common.materialtype", + "fields": { + "comment": "", + "available": true, + "parent": null, + "label": "M\u00e9tal", + "recommendation": "Hygrom\u00e9trie contr\u00f4l\u00e9e, variation de temp\u00e9rature faible", + "txt_idx": "metal" + } + }, + { + "pk": 2, + "model": "ishtar_common.materialtype", + "fields": { + "comment": "", + "available": true, + "parent": null, + "label": "Os", + "recommendation": "Hygrom\u00e9trie contr\u00f4l\u00e9e, variations de temp\u00e9rature faible", + "txt_idx": "bone" + } + }, + { + "pk": 3, + "model": "ishtar_common.materialtype", + "fields": { + "comment": "", + "available": true, + "parent": 2, + "label": "Os animal", + "recommendation": "idem os", + "txt_idx": "animal_bone" + } + }, + { + "pk": 4, + "model": "ishtar_common.materialtype", + "fields": { + "comment": "", + "available": true, + "parent": 2, + "label": "Os humain", + "recommendation": "idem os", + "txt_idx": "human_bone" + } + }, + { + "pk": 5, + "model": "ishtar_common.materialtype", + "fields": { + "comment": "", + "available": true, + "parent": null, + "label": "Verre", + "recommendation": "fragile, oxydation, etc.", + "txt_idx": "glass" + } + }, + { + "pk": 6, + "model": "ishtar_common.materialtype", + "fields": { + "comment": "", + "available": true, + "parent": null, + "label": "C\u00e9ramique", + "recommendation": "a d\u00e9tailler", + "txt_idx": "ceramic" + } + }, + { + "pk": 7, + "model": "ishtar_common.materialtype", + "fields": { + "comment": "", + "available": true, + "parent": null, + "label": "Min\u00e9ral", + "recommendation": "a d\u00e9tailler", + "txt_idx": "mineral" + } + }, + { + "pk": 8, + "model": "ishtar_common.materialtype", + "fields": { + "comment": "", + "available": true, + "parent": null, + "label": "\u00c9cofact", + "recommendation": "on en veut pas !", + "txt_idx": "ecofact" + } + }, + { + "pk": 9, + "model": "ishtar_common.materialtype", + "fields": { + "comment": "", + "available": true, + "parent": 1, + "label": "Bronze", + "recommendation": "blah", + "txt_idx": "bronze" + } + }, + { + "pk": 1, + "model": "ishtar_common.warehousetype", + "fields": { + "comment": "Le mobilier arch\u00e9ologique reste dans ce d\u00e9p\u00f4t le temps d'un traitement puis part ailleurs...", + "available": true, + "txt_idx": "restoration_laboratory", + "label": "Laboratoire de restauration" + } + }, + { + "pk": 2, + "model": "ishtar_common.warehousetype", + "fields": { + "comment": "Ce d\u00e9p\u00f4t est un centre de conservation et d'\u00e9tude. Il est d'ordinaire en convention avec l'\u00e9tat.", + "available": true, + "txt_idx": "cce", + "label": "CCE" + } + }, + { + "pk": 4, + "model": "ishtar_common.warehousetype", + "fields": { + "comment": "Ce d\u00e9p\u00f4t poss\u00e8de une convention avec l'\u00e9tat pour conserver du mobilier qui est sous sa garde.", + "available": true, + "txt_idx": "conventioned_warehouse", + "label": "D\u00e9p\u00f4t conventionn\u00e9" + } + }, + { + "pk": 3, + "model": "ishtar_common.warehousetype", + "fields": { + "comment": "Mobilier pr\u00e9sent dans un lieu de mani\u00e8re ill\u00e9gale : pas de convention, voire de responsabilit\u00e9 exprim\u00e9e...", + "available": true, + "txt_idx": "illegal_warehouse", + "label": "D\u00e9p\u00f4t non conventionn\u00e9" + } + }, + { + "pk": 5, + "model": "ishtar_common.warehousetype", + "fields": { + "comment": "Ce d\u00e9p\u00f4t est sous la responsabilit\u00e9 directe de l'Etat. Il peut en \u00eatre locataire ou propri\u00e9taire.", + "available": true, + "txt_idx": "state_warehouse", + "label": "D\u00e9p\u00f4t de l'Etat" + } + }, + { + "pk": 6, + "model": "ishtar_common.warehousetype", + "fields": { + "comment": "Pour le stockage de documents papier, rapports la plus part du temps.", + "available": true, + "txt_idx": "library", + "label": "Biblioth\u00e8que" + } + }, + { + "pk": 7, + "model": "ishtar_common.warehousetype", + "fields": { + "comment": "Lieu de stockage de documents vari\u00e9s, photos, relev\u00e9s, jusqu'aux rapports.", + "available": true, + "txt_idx": "documentation_center", + "label": "Centre de documentation" + } + }, + { + "pk": 3, + "model": "ishtar_common.acttype", + "fields": { + "comment": "Suite \u00e0 une demande d'avis, les SRA \u00e9met un courrier signalant sa volont\u00e9 de prescrire un diagnostic ou une fouille sur l'emprise du projet en objet.", + "available": true, + "txt_idx": "pos_advice_reply", + "intented_to": "F", + "label": "R\u00e9ponse positive \u00e0 une demande d'avis (art.10)" + } + }, + { + "pk": 4, + "model": "ishtar_common.acttype", + "fields": { + "comment": "Suite \u00e0 une demande d'avis, les SRA \u00e9met un courrier signalant sa volont\u00e9 de NE PAS prescrire un diagnostic ou une fouille sur l'emprise du projet en objet.", + "available": true, + "txt_idx": "neg_advice_reply", + "intented_to": "F", + "label": "R\u00e9ponse n\u00e9gative \u00e0 une demande d'avis (art.10)" + } + }, + { + "pk": 7, + "model": "ishtar_common.acttype", + "fields": { + "comment": "Suite \u00e0 une Saisine (art.8), envoi d'une r\u00e9ponse de non prescription", + "available": true, + "txt_idx": "reply_no_prescription", + "intented_to": "F", + "label": "R\u00e9ponse NON prescription \u00e0 une saisine" + } + }, + { + "pk": 6, + "model": "ishtar_common.acttype", + "fields": { + "comment": "Arr\u00eat\u00e9 donnant l'autorisation \u00e0 une responsable scientifique de fouiller sur un terrain donn\u00e9.", + "available": true, + "txt_idx": "prog_excav_autorization_order", + "intented_to": "O", + "label": "Arr\u00eat\u00e9 d'autorisation de fouille programm\u00e9e" + } + }, + { + "pk": 5, + "model": "ishtar_common.acttype", + "fields": { + "comment": "Arr\u00eat\u00e9 qui donne l'autorisation \u00e0 un Am\u00e9nageur de faire ex\u00e9cuter par un Op\u00e9rateur agr\u00e9e sous la responsabilit\u00e9 d'un Responsable scientifique, une op\u00e9ration.", + "available": true, + "txt_idx": "excavation_autorization_order", + "intented_to": "O", + "label": "Arr\u00eat\u00e9 d'autorisation de fouille pr\u00e9ventive" + } + }, + { + "pk": 2, + "model": "ishtar_common.acttype", + "fields": { + "comment": "Un arr\u00eat\u00e9 prescrivant la r\u00e9alisation d'une fouille sur une surface donn\u00e9e", + "available": true, + "txt_idx": "excavation_order", + "intented_to": "O", + "label": "Arr\u00eat\u00e9 de prescription de fouille" + } + }, + { + "pk": 1, + "model": "ishtar_common.acttype", + "fields": { + "comment": "Un arr\u00eat\u00e9 prescrivant la r\u00e9alisation d'un diagnostic sur une surface donn\u00e9e, SANS pr\u00e9cision du responsable scientifique, SANS pr\u00e9cision de l'op\u00e9rateur", + "available": true, + "txt_idx": "diagnostic_order", + "intented_to": "O", + "label": "Arr\u00eat\u00e9 de diagnostic, sans RS, sans op\u00e9rateur" + } + }, + { + "pk": 8, + "model": "ishtar_common.acttype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "responsible_act", + "intented_to": "O", + "label": "Arr\u00eat\u00e9 de d\u00e9signation de RS" + } + }, + { + "pk": 9, + "model": "ishtar_common.acttype", + "fields": { + "comment": "D\u00e9signation de l'op\u00e9rateur pour un diagnostic : utile dans le cas o\u00f9 un service territorial ET l'INRAP sont en m\u00eame temps comp\u00e9tents pour un territoire donn\u00e9.", + "available": true, + "txt_idx": "operator_designation_act", + "intented_to": "O", + "label": "Arr\u00eat\u00e9 de d\u00e9signation d'op\u00e9rateur" + } + }, + { + "pk": 10, + "model": "ishtar_common.acttype", + "fields": { + "comment": "", + "available": true, + "txt_idx": "thematic_survey_act", + "intented_to": "O", + "label": "Arr\u00eat\u00e9 d'autorisation de prospection th\u00e9matique" + } + }, + { + "pk": 1, + "model": "ishtar_common.containertype", + "fields": { + "comment": "Type de caisse tr\u00e8s commun dans le nord de la France. Pas cher, pas trop gros donc pas trop lourd.\r\n\r\nR\u00e9f\u00e9rences pr\u00e9cises \u00e0 trouver !!!!!", + "available": true, + "reference": "Inconnue", + "label": "Caisse \u00e0 pomme rouge", + "volume": 18, + "width": 20, + "length": null, + "height": 25, + "txt_idx": "red_apple_bin" + } + }, + { + "pk": 2, + "model": "ishtar_common.containertype", + "fields": { + "comment": "L'horrible caisse \u00e0 poisson ou du genre, a changer au plus vite", + "available": true, + "reference": "variable", + "label": "Caisse en polystyr\u00e8ne", + "volume": 0, + "width": 0, + "length": null, + "height": 0, + "txt_idx": "polystyren_bin" + } + }, + { + "pk": 4, + "model": "ishtar_common.containertype", + "fields": { + "comment": "Caisse Alibert grise standard, a pr\u00e9ciser et d\u00e9cliner en fonction des mod\u00e8les.", + "available": true, + "reference": "a pr\u00e9ciser", + "label": "Caisse Alibert standard", + "volume": 0, + "width": 0, + "length": null, + "height": 0, + "txt_idx": "stand_alibert_bin" + } + }, + { + "pk": 6, + "model": "ishtar_common.containertype", + "fields": { + "comment": "", + "available": true, + "reference": "Curver UNIBOX 29 L", + "label": "Curver UNIBOX 29 L", + "volume": 37, + "width": 355, + "length": null, + "height": 245, + "txt_idx": "curver_unibox_29" + } + }, + { + "pk": 7, + "model": "ishtar_common.containertype", + "fields": { + "comment": "", + "available": true, + "reference": "Curver UNIBOX 48 L", + "label": "Curver UNIBOX 48 L", + "volume": 63, + "width": 432, + "length": null, + "height": 280, + "txt_idx": "curver_unibox_48" + } + }, + { + "pk": 5, + "model": "ishtar_common.containertype", + "fields": { + "comment": "", + "available": true, + "reference": "Curver UNIBOX 20 lL", + "label": "Curver UNIBOX 20 L", + "volume": 25, + "width": 350, + "length": null, + "height": 165, + "txt_idx": "curver_unibox_20" + } + }, + { + "pk": 1, + "model": "ishtar_common.treatmenttype", + "fields": { + "comment": "Le fait de mettre du mobilier dans un contenant. Que cela soit le conditionnement initial ou un re-conditionnement. ", + "available": true, + "txt_idx": "packaging", + "virtual": false, + "label": "Conditionnement" + } + }, + { + "pk": 2, + "model": "ishtar_common.treatmenttype", + "fields": { + "comment": "Un lot mobilier ou un objet isol\u00e9 subit une radiographie (rayon X) qui produit un ou des films radio.", + "available": true, + "txt_idx": "regular_x_ray", + "virtual": false, + "label": "Radiographie argentique" + } + }, + { + "pk": 3, + "model": "ishtar_common.treatmenttype", + "fields": { + "comment": "Un lot mobilier ou un objet isol\u00e9 subit une radiographie (rayon X) qui produit un ou des fichiers num\u00e9riques.", + "available": true, + "txt_idx": "digital_x_ray", + "virtual": false, + "label": "Radiographie num\u00e9rique" + } + }, + { + "pk": 4, + "model": "ishtar_common.treatmenttype", + "fields": { + "comment": "D\u00e9placement de mobilier, entre deux d\u00e9p\u00f4ts : le mobilier ne peut pas \u00eatre stocker ailleurs que dans un lieu consid\u00e9r\u00e9 comme un d\u00e9p\u00f4t.", + "available": true, + "txt_idx": "moving", + "virtual": false, + "label": "D\u00e9placement" + } + }, + { + "pk": 5, + "model": "ishtar_common.treatmenttype", + "fields": { + "comment": "Regroupement d'un ensemble de mobilier. Exemple : ensemble des outils provenant d'une fouille, Mobilier datant d'un site, tessonier virtuel, etc.", + "available": true, + "txt_idx": "virtual_group", + "virtual": true, + "label": "Groupement virtuel" + } + }, + { + "pk": 7, + "model": "ishtar_common.treatmenttype", + "fields": { + "comment": "Division d'un lot de mobilier en plusieurs lots", + "available": true, + "txt_idx": "split", + "virtual": false, + "label": "Division" + } + }, + { + "pk": 6, + "model": "ishtar_common.treatmenttype", + "fields": { + "comment": "R\u00e9union de plusieurs objets ou lots mobiliers en un seul. Ce type de traitement peut impliquer ou non un reconditionnement.\r\n\r\nExemple : Remontage d'une c\u00e9ramique \u00e0 partir de tessons d\u00e9j\u00e0 pr\u00e9sents dans un contenant (pas de reconditionnement), regroupement d'une partie de la faune (os) d'une op\u00e9ration et cr\u00e9ation d'une nouvelle caisse dans ce but (reconditionnement \u00e0 faire)", + "available": true, + "txt_idx": "physical_grouping", + "virtual": false, + "label": "Groupement" + } + }, + { + "pk": 8, + "model": "ishtar_common.treatmenttype", + "fields": { + "comment": "Prise de vue \u00e0 l'aide d'un appareil photo num\u00e9rique", + "available": true, + "txt_idx": "digital_photography", + "virtual": false, + "label": "Photographie num\u00e9rique" + } + }, + { + "pk": 9, + "model": "ishtar_common.treatmenttype", + "fields": { + "comment": "Photographie produisant un film (positif ou n\u00e9gatif)", + "available": true, + "txt_idx": "regular_photography", + "virtual": false, + "label": "Photographie argentique" + } + }, + { + "pk": 10, + "model": "ishtar_common.treatmenttype", + "fields": { + "comment": "Processus qui permet \u00e9liminer le sel qui impr\u00e8gne un objet arch\u00e9ologique ou lot d'objets.", + "available": true, + "txt_idx": "desalinisation", + "virtual": false, + "label": "D\u00e9salinisation" + } + }, + { + "pk": 11, + "model": "ishtar_common.treatmenttype", + "fields": { + "comment": "R\u00e9duction des oxydes d\u00e9velopp\u00e9s sur/dans un objet arch\u00e9ologique par l'usage de courant \u00e9lectrique.", + "available": true, + "txt_idx": "electrolysis", + "virtual": false, + "label": "Electrolyse" + } + } +] diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py new file mode 100644 index 000000000..62f51fa08 --- /dev/null +++ b/ishtar_common/forms.py @@ -0,0 +1,249 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Forms definition +""" +import datetime +import re +from itertools import groupby + +from django import forms +from django.conf import settings +from django.contrib.auth.models import User +from django.contrib.sites.models import Site +from django.core.urlresolvers import reverse +from django.core import validators +from django.core.exceptions import ObjectDoesNotExist +from django.core.mail import send_mail +from django.db.models import Max +from django.forms.formsets import formset_factory, BaseFormSet, \ + DELETION_FIELD_NAME +from django.shortcuts import render_to_response +from django.template import Context, RequestContext, loader +from django.utils import formats +from django.utils.functional import lazy +from django.utils.translation import ugettext_lazy as _ + +# from formwizard.forms import NamedUrlSessionFormWizard + +class NamedUrlSessionFormWizard(forms.Form): + def __init__(self, form_list, condition_list={}, url_name=''): + self.form_list = dict(form_list) + self.condition_list = condition_list + self.url_name = url_name + super(NamedUrlSessionFormWizard, self).__init__(self) + + + def rindex(self, idx): + return self.url_name.rindex(idx) + +import models +import widgets + +reverse_lazy = lazy(reverse, unicode) + +regexp_name = re.compile(r'^[\w\- ]+$', re.UNICODE) +name_validator = validators.RegexValidator(regexp_name, +_(u"Enter a valid name consisting of letters, spaces and hyphens."), 'invalid') + +class FloatField(forms.FloatField): + """ + Allow the use of comma for separating float fields + """ + def clean(self, value): + if value: + value = value.replace(',', '.').replace('%', '') + return super(FloatField, self).clean(value) + +class FinalForm(forms.Form): + final = True + form_label = _(u"Confirm") + +class FormSet(BaseFormSet): + def check_duplicate(self, key_names, error_msg=""): + """Check for duplicate items in the formset""" + if any(self.errors): + return + if not error_msg: + error_msg = _("There are identical items.") + items = [] + for i in range(0, self.total_form_count()): + form = self.forms[i] + if not form.is_valid(): + continue + item = [key_name in form.cleaned_data and form.cleaned_data[key_name] + for key_name in key_names] + if not [v for v in item if v]: + continue + if item in items: + raise forms.ValidationError, error_msg + items.append(item) + + def add_fields(self, form, index): + super(FormSet, self).add_fields(form, index) + form.fields[DELETION_FIELD_NAME].label = '' + form.fields[DELETION_FIELD_NAME].widget = widgets.DeleteWidget() + +''' +class SearchWizard(NamedUrlSessionFormWizard): + model = None + + def get_wizard_name(self): + """ + As the class name can interfere when reused, use the url_name + """ + return self.url_name + + def get_template(self, request, storage): + templates = ['search.html'] + return templates + +def get_now(): + format = formats.get_format('DATE_INPUT_FORMATS')[0] + value = datetime.datetime.now().strftime(format) + return value + +class DeletionWizard(Wizard): + def get_formated_datas(self, forms): + datas = super(DeletionWizard, self).get_formated_datas(forms) + self.current_obj = None + for form in forms: + if not hasattr(form, "cleaned_data"): + continue + for key in form.cleaned_data: + if key == 'pk': + model = form.associated_models['pk'] + self.current_obj = model.objects.get(pk=form.cleaned_data['pk']) + if not self.current_obj: + return datas + res = {} + for field in self.model._meta.fields + self.model._meta.many_to_many: + if field.name not in self.fields: + continue + value = getattr(self.current_obj, field.name) + if not value: + continue + if hasattr(value, 'all'): + value = ", ".join([unicode(item) for item in value.all()]) + if not value: + continue + else: + value = unicode(value) + res[field.name] = (field.verbose_name, value, '') + if not datas and self.fields: + datas = [['', []]] + for field in self.fields: + if field in res: + datas[0][1].append(res[field]) + return datas + + def done(self, request, storage, form_list, **kwargs): + obj = self.get_current_object(request, storage) + obj.delete() + return render_to_response('wizard_delete_done.html', {}, + context_instance=RequestContext(request)) + +class ClosingDateFormSelection(forms.Form): + form_label = _("Closing date") + end_date = forms.DateField(label=_(u"Closing date"), + widget=widgets.JQueryDate) + +class ClosingWizard(Wizard): + # "close" an item + # to be define in the overloaded class + model = None + fields = [] + + def get_formated_datas(self, forms): + datas = super(ClosingWizard, self).get_formated_datas(forms) + self.current_obj = None + for form in forms: + if not hasattr(form, "cleaned_data"): + continue + for key in form.cleaned_data: + if key == 'pk': + model = form.associated_models['pk'] + self.current_obj = model.objects.get( + pk=form.cleaned_data['pk']) + if not self.current_obj: + return datas + res = {} + for field in self.model._meta.fields + self.model._meta.many_to_many: + if field.name not in self.fields: + continue + value = getattr(self.current_obj, field.name) + if not value: + continue + if hasattr(value, 'all'): + value = ", ".join([unicode(item) for item in value.all()]) + if not value: + continue + else: + value = unicode(value) + res[field.name] = (field.verbose_name, value, '') + if not datas and self.fields: + datas = [['', []]] + for field in self.fields: + if field in res: + datas[0][1].append(res[field]) + return datas + + def done(self, request, storage, form_list, **kwargs): + obj = self.get_current_object(request, storage) + for form in form_list: + if form.is_valid(): + if 'end_date' in form.cleaned_data and hasattr(obj, 'end_date'): + obj.end_date = form.cleaned_data['end_date'] + obj.save() + return render_to_response('wizard_closing_done.html', {}, + context_instance=RequestContext(request)) + +def get_form_selection(class_name, label, key, model, base_form, get_url, + not_selected_error=_(u"You should select an item."), new=False, + new_message=_(u"Add a new item")): + """ + Generate a class selection form + class_name -- name of the class + label -- label of the form + key -- model, + base_form -- base form to select + get_url -- url to get the item + not_selected_error -- message displayed when no item is selected + new -- can add new items + new_message -- message of link to add new items + """ + attrs = {'_main_key':key, + '_not_selected_error':not_selected_error, + 'form_label':label, + 'associated_models':{key:model}, + 'currents':{key:model},} + attrs[key] = forms.IntegerField(label="", required=False, + validators=[models.valid_id(model)], + widget=widgets.JQueryJqGrid(reverse_lazy(get_url), base_form(), model, + new=new, new_message=new_message)) + def clean(self): + cleaned_data = self.cleaned_data + if self._main_key not in cleaned_data \ + or not cleaned_data[self._main_key]: + raise forms.ValidationError(self._not_selected_error) + return cleaned_data + attrs['clean'] = clean + return type(class_name, (forms.Form,), attrs) +''' diff --git a/ishtar_common/forms_common.py b/ishtar_common/forms_common.py new file mode 100644 index 000000000..d034f6ddf --- /dev/null +++ b/ishtar_common/forms_common.py @@ -0,0 +1,518 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Administrative forms definitions: manage accounts and persons +""" +import datetime + +from django import forms +from django.conf import settings +from django.contrib.auth.models import User +from django.contrib.sites.models import Site +from django.core import validators +from django.core.mail import send_mail +from django.core.exceptions import ObjectDoesNotExist +from django.forms.formsets import formset_factory, DELETION_FIELD_NAME +from django.template import Context, RequestContext, loader +from django.shortcuts import render_to_response +from django.utils.safestring import mark_safe +from django.utils.translation import ugettext_lazy as _ + +import models +import widgets +from forms import FinalForm, FormSet, reverse_lazy, name_validator + +def get_town_field(label=_(u"Town"), required=True): + help_text = _(u"<p>Type name, department code and/or postal code of the " + u"town you would like to select. The search is insensitive to case.</p>\n" + u"<p>Only the first twenty results are displayed but specifying the " + u"department code is generally sufficient to get the appropriate result.</p>" + u"\n<p class='example'>For instance type \"saint denis 93\" for getting " + u"the french town Saint-Denis in the Seine-Saint-Denis department.</p>") + # !FIXME hard_link, reverse_lazy doen't seem to work with formsets + return forms.IntegerField( + widget=widgets.JQueryAutoComplete("/" + settings.URL_PATH + \ + 'autocomplete-town', associated_model=models.Town), + validators=[models.valid_id(models.Town)], label=label, + help_text=mark_safe(help_text), required=required) + +def get_person_field(label=_(u"Person"), required=True, person_type=None): + # !FIXME hard_link, reverse_lazy doen't seem to work with formsets + widget = None + url = "/" + settings.URL_PATH + 'autocomplete-person' + if person_type: + if isinstance(person_type, unicode) or isinstance(person_type, str): + person_type = models.PersonType.objects.get(txt_idx=person_type) + url += u"/" + unicode(person_type.pk) + widget = widgets.JQueryAutoComplete(url, associated_model=models.Person) + return forms.IntegerField(widget=widget, label=label, required=required, + validators=[models.valid_id(models.Person)]) + +def get_warehouse_field(label=_(u"Warehouse"), required=True): + # !FIXME hard_link, reverse_lazy doen't seem to work with formsets + url = "/" + settings.URL_PATH + 'autocomplete-warehouse' + widget = widgets.JQueryAutoComplete(url, associated_model=models.Warehouse) + return forms.IntegerField(widget=widget, label=label, required=required, + validators=[models.valid_id(models.Warehouse)]) + +class WarehouseForm(forms.Form): + name = forms.CharField(label=_(u"Name"), max_length=40, + validators=[name_validator]) + warehouse_type = forms.ChoiceField(label=_(u"Warehouse type"), + choices=[]) + person_in_charge = forms.IntegerField(label=_(u"Person in charge"), + widget=widgets.JQueryAutoComplete( + reverse_lazy('autocomplete-person'), associated_model=models.Person), + validators=[models.valid_id(models.Person)], + required=False) + comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea, + required=False) + address = forms.CharField(label=_(u"Address"), widget=forms.Textarea, + required=False) + address_complement = forms.CharField(label=_(u"Address complement"), + widget=forms.Textarea, required=False) + postal_code = forms.CharField(label=_(u"Postal code"), max_length=10, + required=False) + town = forms.CharField(label=_(u"Town"), max_length=30, required=False) + country = forms.CharField(label=_(u"Country"), max_length=30, + required=False) + phone = forms.CharField(label=_(u"Phone"), max_length=18, required=False) + mobile_phone = forms.CharField(label=_(u"Town"), max_length=18, + required=False) + + def __init__(self, *args, **kwargs): + super(WarehouseForm, self).__init__(*args, **kwargs) + self.fields['warehouse_type'].choices = \ + models.WarehouseType.get_types() + self.fields['warehouse_type'].help_text = \ + models.WarehouseType.get_help() + + def save(self, user): + dct = self.cleaned_data + dct['history_modifier'] = user + dct['warehouse_type'] = models.WarehouseType.objects.get( + pk=dct['warehouse_type']) + if 'person_in_charge' in dct and dct['person_in_charge']: + dct['person_in_charge'] = models.Person.objects.get( + pk=dct['person_in_charge']) + new_item = models.Warehouse(**dct) + new_item.save() + return new_item + +class OrganizationForm(forms.Form): + name = forms.CharField(label=_(u"Name"), max_length=40, + validators=[name_validator]) + organization_type = forms.ChoiceField(label=_(u"Organization type"), + choices=[]) + address = forms.CharField(label=_(u"Address"), widget=forms.Textarea, + required=False) + address_complement = forms.CharField(label=_(u"Address complement"), + widget=forms.Textarea, required=False) + postal_code = forms.CharField(label=_(u"Postal code"), max_length=10, + required=False) + town = forms.CharField(label=_(u"Town"), max_length=30, required=False) + country = forms.CharField(label=_(u"Country"), max_length=30, + required=False) + phone = forms.CharField(label=_(u"Phone"), max_length=18, required=False) + mobile_phone = forms.CharField(label=_(u"Town"), max_length=18, + required=False) + + def __init__(self, *args, **kwargs): + super(OrganizationForm, self).__init__(*args, **kwargs) + self.fields['organization_type'].choices = \ + models.OrganizationType.get_types() + self.fields['organization_type'].help_text = \ + models.OrganizationType.get_help() + + def save(self, user): + dct = self.cleaned_data + dct['history_modifier'] = user + dct['organization_type'] = models.OrganizationType.objects.get( + pk=dct['organization_type']) + new_item = models.Organization(**dct) + new_item.save() + return new_item + +class PersonFormSelection(forms.Form): + form_label = _(u"Person search") + associated_models = {'pk':models.Person} + currents = {'pk':models.Person} + pk = forms.IntegerField(label=_("Person"), + widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person'), + associated_model=models.Person), + validators=[models.valid_id(models.Person)]) + +class PersonForm(forms.Form): + form_label = _("Identity") + associated_models = {'attached_to':models.Organization, + 'person_type':models.PersonType} + title = forms.ChoiceField(label=_("Title"), choices=models.Person.TYPE) + surname = forms.CharField(label=_(u"Surname"), max_length=20, + validators=[name_validator]) + name = forms.CharField(label=_(u"Name"), max_length=30, + validators=[name_validator]) + email = forms.CharField(label=_(u"Email"), max_length=40, required=False, + validators=[validators.validate_email]) + person_type = forms.ChoiceField(label=_("Person type"), + choices=[]) + attached_to = forms.IntegerField(label=_("Current organization"), + widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-organization'), + associated_model=models.Organization, new=True), + validators=[models.valid_id(models.Organization)], required=False) + + def __init__(self, *args, **kwargs): + super(PersonForm, self).__init__(*args, **kwargs) + self.fields['person_type'].choices = models.PersonType.get_types() + self.fields['person_type'].help_text = models.PersonType.get_help() + + def save(self, user): + dct = self.cleaned_data + dct['history_modifier'] = user + dct['person_type'] = models.PersonType.objects.get( + pk=dct['person_type']) + if 'attached_to' in dct and dct['attached_to']: + dct['attached_to'] = models.Organization.objects.get( + pk=dct['attached_to']) + new_item = models.Person(**dct) + new_item.save() + return new_item + +''' +person_search_wizard = SearchWizard([ + ('general-person_search', PersonFormSelection)], + url_name='person_search',) + + + +person_modification_wizard = PersonWizard([ + ('selec-person_modification', PersonFormSelection), + ('identity-person_modification', PersonForm), + ('final-person_modification', FinalForm)], + url_name='person_modification',) + +class AccountWizard(Wizard): + model = models.Person + def get_formated_datas(self, forms): + datas = super(AccountWizard, self).get_formated_datas(forms) + for form in forms: + if not hasattr(form, "cleaned_data"): + continue + for key in form.cleaned_data: + if key == 'hidden_password' and form.cleaned_data[key]: + datas[-1][1].append((_("New password"), "*"*8)) + return datas + + def done(self, request, storage, form_list, **kwargs): + """ + Save the account + """ + dct = {} + for form in form_list: + if not form.is_valid(): + return self.render(request, storage, form) + associated_models = hasattr(form, 'associated_models') and \ + form.associated_models or {} + if type(form.cleaned_data) == dict: + for key in form.cleaned_data: + if key == 'pk': + continue + value = form.cleaned_data[key] + if key in associated_models and value: + value = associated_models[key].objects.get(pk=value) + dct[key] = value + person = self.get_current_object(request, storage) + if not person: + return self.render(request, storage, form) + for key in dct.keys(): + if key.startswith('hidden_password'): + dct['password'] = dct.pop(key) + try: + account = models.IshtarUser.objects.get(person=person) + account.username = dct['username'] + account.email = dct['email'] + except ObjectDoesNotExist: + now = datetime.datetime.now() + account = models.IshtarUser(person=person, username=dct['username'], + email=dct['email'], first_name=person.surname, + last_name=person.name, is_staff=False, is_active=True, + is_superuser=False, last_login=now, date_joined=now) + if dct['password']: + account.set_password(dct['password']) + account.save() + + if 'send_password' in dct and dct['send_password'] and \ + settings.ADMINS: + site = Site.objects.get_current() + + app_name = site and ("Ishtar - " + site.name) \ + or "Ishtar" + context = Context({'login':dct['username'], + 'password':dct['password'], + 'app_name':app_name, + 'site': site and site.domain or "" + }) + t = loader.get_template('account_activation_email.txt') + msg = t.render(context) + subject = _(u"[%(app_name)s] Account creation/modification") % { + "app_name":app_name} + send_mail(subject, msg, settings.ADMINS[0][1], + [dct['email']], fail_silently=True) + res = render_to_response('wizard_done.html', {}, + context_instance=RequestContext(request)) + return res + + def get_form(self, request, storage, step=None, data=None, files=None): + """ + Display the "Send email" field if necessary + """ + form = super(AccountWizard, self).get_form(request, storage, step, data, + files) + if not hasattr(form, 'is_hidden'): + return form + if self.session_get_value(request, storage, + 'account-account_management', 'hidden_password'): + form.is_hidden = False + return form + +''' +class AccountForm(forms.Form): + form_label = _("Account") + associated_models = {'pk':models.Person} + currents = {'pk':models.Person} + pk = forms.IntegerField(label=u"", widget=forms.HiddenInput, required=False) + username = forms.CharField(label=_(u"Account"), max_length=30) + email = forms.CharField(label=_(u"Email"), max_length=75, + validators=[validators.validate_email]) + hidden_password = forms.CharField(label=_(u"New password"), max_length=128, + widget=forms.PasswordInput, required=False, + validators=[validators.MinLengthValidator(4)]) + hidden_password_confirm = forms.CharField( + label=_(u"New password (confirmation)"), max_length=128, + widget=forms.PasswordInput, required=False) + + def __init__(self, *args, **kwargs): + if 'initial' in kwargs and 'pk' in kwargs['initial']: + try: + person = models.Person.objects.get(pk=kwargs['initial']['pk']) + account = models.IshtarUser.objects.get(person=person) + kwargs['initial'].update({'username':account.username, + 'email':account.email}) + except ObjectDoesNotExist: + pass + return super(AccountForm, self).__init__(*args, **kwargs) + + def clean(self): + cleaned_data = self.cleaned_data + password = cleaned_data.get("hidden_password") + if password and password != cleaned_data.get("hidden_password_confirm"): + raise forms.ValidationError(_(u"Your password and confirmation " + u"password do not match.")) + if not cleaned_data.get("pk"): + models.is_unique(User, 'username')(cleaned_data.get("username")) + if not password: + raise forms.ValidationError(_(u"You must provide a correct \ +password.")) + # check username unicity + usernames = models.IshtarUser.objects.filter(username= + cleaned_data.get('username')) + if cleaned_data.get('pk'): + usernames.exclude(pk=cleaned_data.get('pk')) + if usernames.count(): + raise forms.ValidationError(_(u"This username already exists.")) + return cleaned_data + +class FinalAccountForm(forms.Form): + final = True + form_label = _("Confirm") + send_password = forms.BooleanField(label=_(u"Send the new password by " + u"email?"), required=False) + + def __init__(self, *args, **kwargs): + self.is_hidden = True + return super(FinalAccountForm, self).__init__(*args, **kwargs) +''' +account_management_wizard = AccountWizard([ + ('selec-account_management', PersonFormSelection), + ('account-account_management', AccountForm), + ('final-account_management', FinalAccountForm)], + url_name='account_management',) +''' +class TownForm(forms.Form): + form_label = _("Towns") + base_model = 'town' + associated_models = {'town':models.Town} + town = get_town_field(required=False) + +class TownFormSet(FormSet): + def clean(self): + """Checks that no towns are duplicated.""" + return self.check_duplicate(('town',), + _("There are identical towns.")) + +TownFormset = formset_factory(TownForm, can_delete=True, formset=TownFormSet) +TownFormset.form_label = _("Towns") + +class ParcelForm(forms.Form): + form_label = _("Parcels") + base_model = 'parcel' + associated_models = {'parcel':models.Parcel, 'town':models.Town} + town = forms.ChoiceField(label=_("Town"), choices=(), required=False, + validators=[models.valid_id(models.Town)]) + section = forms.CharField(label=_(u"Section"), required=False, + validators=[validators.MaxLengthValidator(4)]) + parcel_number = forms.CharField(label=_(u"Parcel number"), required=False, + validators=[validators.MaxLengthValidator(6)]) + year = forms.IntegerField(label=_("Year"), required=False, + validators=[validators.MinValueValidator(1900), + validators.MaxValueValidator(2100)]) + def __init__(self, *args, **kwargs): + towns = None + if 'data' in kwargs and 'TOWNS' in kwargs['data']: + towns = kwargs['data']['TOWNS'] + # clean data if not "real" data + prefix_value = kwargs['prefix'] + '-town' + if not [k for k in kwargs['data'].keys() + if k.startswith(prefix_value) and kwargs['data'][k]]: + kwargs['data'] = None + if 'files' in kwargs: + kwargs.pop('files') + super(ParcelForm, self).__init__(*args, **kwargs) + if towns: + self.fields['town'].choices = [('', '--')] + towns + + def clean(self): + """Check required fields""" + if any(self.errors): + return + if not self.cleaned_data or DELETION_FIELD_NAME in self.cleaned_data \ + and self.cleaned_data[DELETION_FIELD_NAME]: + return + for key in ('town', 'parcel_number', 'section'): + if not key in self.cleaned_data or not self.cleaned_data[key]: + raise forms.ValidationError(_(u"Town section and parcel number " + u"fields are required.")) + return self.cleaned_data + + +class ParcelFormSet(FormSet): + def clean(self): + """Checks that no parcels are duplicated.""" + return self.check_duplicate(('town', 'parcel_number', 'year'), + _(u"There are identical parcels.")) + +ParcelFormSet = formset_factory(ParcelForm, can_delete=True, + formset=ParcelFormSet) +ParcelFormSet.form_label = _(u"Parcels") + +###################### +# Sources management # +###################### +''' +class SourceWizard(Wizard): + model = None + def get_extra_model(self, dct, request, storage, form_list): + dct = super(SourceWizard, self).get_extra_model(dct, request, storage, + form_list) + if 'history_modifier' in dct: + dct.pop('history_modifier') + return dct +''' +class SourceForm(forms.Form): + form_label = _(u"Documentation informations") + associated_models = {'source_type':models.SourceType} + title = forms.CharField(label=_(u"Title"), + validators=[validators.MaxLengthValidator(200)]) + source_type = forms.ChoiceField(label=_(u"Source type"), choices=[]) + associated_url = forms.URLField(required=False, + label=_(u"Numerical ressource (web address)")) + receipt_date = forms.DateField(label=_(u"Receipt date"), required=False, + widget=widgets.JQueryDate) + creation_date = forms.DateField(label=_(u"Creation date"), required=False, + widget=widgets.JQueryDate) + + def __init__(self, *args, **kwargs): + super(SourceForm, self).__init__(*args, **kwargs) + self.fields['source_type'].choices = models.SourceType.get_types() + +class SourceSelect(forms.Form): + authors = forms.IntegerField( + widget=widgets.JQueryAutoComplete("/" + settings.URL_PATH + \ + 'autocomplete-author', associated_model=models.Author), + validators=[models.valid_id(models.Author)], label=_(u"Author"), + required=False) + + source_type = forms.ChoiceField(label=_("Source type"), choices=[]) + + def __init__(self, *args, **kwargs): + super(SourceSelect, self).__init__(*args, **kwargs) + self.fields['source_type'].choices = models.SourceType.get_types() + self.fields['source_type'].help_text = models.SourceType.get_help() + +class SourceDeletionForm(FinalForm): + confirm_msg = " " + confirm_end_msg = _(u"Would you like to delete this documentation?") + +###################### +# Authors management # +###################### + +class AuthorForm(forms.Form): + form_label = _(u"Author") + associated_models = {'person':models.Person, + 'author_type':models.AuthorType} + person = forms.IntegerField( + widget=widgets.JQueryAutoComplete("/" + settings.URL_PATH + \ + 'autocomplete-person', associated_model=models.Person, new=True), + validators=[models.valid_id(models.Person)], label=_(u"Person")) + author_type = forms.ChoiceField(label=_(u"Author type"), choices=[]) + + def __init__(self, *args, **kwargs): + super(AuthorForm, self).__init__(*args, **kwargs) + self.fields['author_type'].choices = models.AuthorType.get_types() + + def save(self, user): + dct = self.cleaned_data + dct['author_type'] = models.AuthorType.objects.get( + pk=dct['author_type']) + dct['person'] = models.Person.objects.get(pk=dct['person']) + new_item = models.Author(**dct) + new_item.save() + return new_item + + +class AuthorFormSelection(forms.Form): + form_label = _(u"Author selection") + base_model = 'author' + associated_models = {'author':models.Author} + author = forms.IntegerField( + widget=widgets.JQueryAutoComplete("/" + settings.URL_PATH + \ + 'autocomplete-author', associated_model=models.Author, new=True), + validators=[models.valid_id(models.Author)], label=_(u"Author")) + +class AuthorFormSet(FormSet): + def clean(self): + """Checks that no author are duplicated.""" + return self.check_duplicate(('author',), + _("There are identical authors.")) + +AuthorFormset = formset_factory(AuthorFormSelection, can_delete=True, + formset=AuthorFormSet) +AuthorFormset.form_label = _("Authors") + diff --git a/ishtar_common/forms_context_records.py b/ishtar_common/forms_context_records.py new file mode 100644 index 000000000..816782bd8 --- /dev/null +++ b/ishtar_common/forms_context_records.py @@ -0,0 +1,362 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Context records forms definitions +""" +import datetime +from itertools import groupby + +from django import forms +from django.core import validators +from django.core.exceptions import ObjectDoesNotExist +from django.db.models import Max +from django.utils.translation import ugettext_lazy as _ + +from ishtar import settings + +import models +import widgets +from forms import Wizard, FinalForm, FormSet, SearchWizard, DeletionWizard, \ + formset_factory, get_now, reverse_lazy, get_form_selection +from forms_common import get_town_field, SourceForm, SourceWizard, \ + SourceSelect, AuthorFormset +from forms_operations import OperationSelect + +class RecordWizard(Wizard): + model = models.ContextRecord + edit = False + + def get_current_operation(self, request, storage): + step = storage.get_current_step() + if not step: + return + if step.endswith('_creation'): # an operation has been selected + main_form_key = 'selec-' + self.url_name + try: + idx = int(self.session_get_value(request, storage, + main_form_key, 'operation_id')) + current_ope = models.Operation.objects.get(pk=idx) + return current_ope + except(TypeError, ValueError, ObjectDoesNotExist): + pass + current_cr = self.get_current_object(request, storage) + if current_cr: + return current_cr.parcel.operation + + def get_template_context(self, request, storage, form=None): + """ + Get the operation "reminder" on top of wizard forms + """ + context = super(RecordWizard, self).get_template_context(request, + storage, form) + operation = self.get_current_operation(request, storage) + if not operation: + return context + items = [] + if hasattr(operation, 'code_patriarche') and operation.code_patriarche: + items.append(unicode(operation.code_patriarche)) + items.append("-".join((unicode(operation.year), + unicode(operation.operation_code)))) + context['reminder'] = _("Current operation: ") + " - ".join(items) + return context + + def get_form(self, request, storage, step=None, data=None, files=None): + """ + Get associated operation + """ + if data: + data = data.copy() + else: + data = {} + if not step: + step = self.determine_step(request, storage) + form = self.get_form_list(request, storage)[step] + + general_form_key = 'general-' + self.url_name + if step.startswith('general-'): + if step.endswith('_creation'): # an operation has been selected + main_form_key = 'selec-' + self.url_name + try: + idx = int(self.session_get_value(request, storage, + main_form_key, 'operation_id')) + current_obj = models.Operation.objects.get(pk=idx) + data['operation'] = current_obj + except(TypeError, ValueError, ObjectDoesNotExist): + pass + else: + current_object = self.get_current_object(request, storage) + data['context_record'] = current_object + form = super(RecordWizard, self).get_form(request, storage, step, data, + files) + return form + +class RecordModifWizard(RecordWizard): + modification = True + model = models.ContextRecord + +class RecordSelect(forms.Form): + parcel__town = get_town_field() + operation__year = forms.IntegerField(label=_(u"Year")) + datings__period = forms.ChoiceField(label=_(u"Period"), choices=[]) + unit = forms.ChoiceField(label=_(u"Unit type"), choices=[]) + def __init__(self, *args, **kwargs): + super(RecordSelect, self).__init__(*args, **kwargs) + self.fields['datings__period'].choices = \ + models.Period.get_types() + self.fields['datings__period'].help_text = \ + models.Period.get_help() + self.fields['unit'].choices = models.Unit.get_types() + self.fields['unit'].help_text = models.Unit.get_help() + +class RecordFormSelection(forms.Form): + form_label = _("Context record search") + associated_models = {'pk':models.ContextRecord} + currents = {'pk':models.ContextRecord} + pk = forms.IntegerField(label="", required=False, + widget=widgets.JQueryJqGrid(reverse_lazy('get-contextrecord'), + RecordSelect(), models.ContextRecord, + source_full=reverse_lazy('get-contextrecord-full')), + validators=[models.valid_id(models.ContextRecord)]) + + def clean(self): + cleaned_data = self.cleaned_data + if 'pk' not in cleaned_data or not cleaned_data['pk']: + raise forms.ValidationError(_(u"You should at least select one " + u"context record.")) + return cleaned_data + + +class RecordFormGeneral(forms.Form): + form_label = _("General") + associated_models = {'parcel':models.Parcel, 'unit':models.Unit} + pk = forms.IntegerField(required=False, widget=forms.HiddenInput) + operation_id = forms.IntegerField(widget=forms.HiddenInput) + parcel = forms.ChoiceField(label=_("Parcel"), choices=[]) + label = forms.CharField(label=_(u"ID"), + validators=[validators.MaxLengthValidator(200)]) + description = forms.CharField(label=_(u"Description"), + widget=forms.Textarea, required=False) + length = forms.IntegerField(label=_(u"Length (cm)"), required=False) + width = forms.IntegerField(label=_(u"Width (cm)"), required=False) + thickness = forms.IntegerField(label=_(u"Thickness (cm)"), required=False) + depth = forms.IntegerField(label=_(u"Depth (cm)"), required=False) + unit = forms.ChoiceField(label=_("Unit"), required=False, + choices=models.Unit.get_types()) + location = forms.CharField(label=_(u"Location"), widget=forms.Textarea, + required=False, validators=[validators.MaxLengthValidator(200)]) + + def __init__(self, *args, **kwargs): + operation = None + if 'data' in kwargs and kwargs['data'] and \ + ('operation' in kwargs['data'] or 'context_record' in kwargs['data']): + if 'operation' in kwargs['data']: + operation = kwargs['data']['operation'] + if 'context_record' in kwargs['data'] and \ + kwargs['data']['context_record']: + operation = kwargs['data']['context_record'].operation + # clean data if not "real" data + prefix_value = kwargs['prefix'] + if not [k for k in kwargs['data'].keys() + if k.startswith(kwargs['prefix']) and kwargs['data'][k]]: + kwargs['data'] = None + if 'files' in kwargs: + kwargs.pop('files') + super(RecordFormGeneral, self).__init__(*args, **kwargs) + self.fields['parcel'].choices = [('', '--')] + if operation: + self.fields['operation_id'].initial = operation.pk + parcels = operation.parcels.all() + sort = lambda x: (x.town.name, x.section) + parcels = sorted(parcels, key=sort) + for key, gparcels in groupby(parcels, sort): + self.fields['parcel'].choices.append( + (" - ".join(key), [(parcel.pk, parcel.short_label()) for parcel in gparcels]) + ) + + def clean(self): + # manage unique context record ID + cleaned_data = self.cleaned_data + operation_id = cleaned_data.get("operation_id") + label = cleaned_data.get("label") + cr = models.ContextRecord.objects.filter(label=label, + parcel__operation__pk=operation_id) + if 'pk' in cleaned_data and cleaned_data['pk']: + cr = cr.exclude(pk=cleaned_data['pk']) + if cr.count(): + raise forms.ValidationError(_(u"This ID already exist for " + u"this operation.")) + return cleaned_data + +class DatingForm(forms.Form): + form_label = _("Dating") + base_model = 'dating' + associated_models = {'dating_type':models.DatingType, + 'quality':models.DatingQuality, + 'period':models.Period} + period = forms.ChoiceField(label=_("Period"), + choices=models.Period.get_types()) + start_date = forms.IntegerField(label=_(u"Start date"), required=False) + end_date = forms.IntegerField(label=_(u"End date"), required=False) + quality = forms.ChoiceField(label=_("Quality"), required=False, + choices=models.DatingQuality.get_types()) + dating_type = forms.ChoiceField(label=_("Dating type"), required=False, + choices=[]) + + def __init__(self, *args, **kwargs): + super(DatingForm, self).__init__(*args, **kwargs) + self.fields['dating_type'].choices = models.DatingType.get_types() + self.fields['dating_type'].help_text = models.DatingType.get_help() + + +DatingFormSet = formset_factory(DatingForm, can_delete=True, + formset=FormSet) +DatingFormSet.form_label = _("Dating") + +class RecordFormInterpretation(forms.Form): + form_label = _("Interpretation") + associated_models = {'activity':models.ActivityType, + 'identification':models.IdentificationType,} + has_furniture = forms.NullBooleanField(label=_(u"Has furniture?"), + required=False) + filling = forms.CharField(label=_(u"Filling"), + widget=forms.Textarea, required=False) + interpretation = forms.CharField(label=_(u"Interpretation"), + widget=forms.Textarea, required=False) + activity = forms.ChoiceField(label=_(u"Activity"), required=False, + choices=[]) + identification = forms.ChoiceField(label=_("Identification"), + required=False, choices=[]) + taq = forms.IntegerField(label=_(u"TAQ"), required=False) + taq_estimated = forms.IntegerField(label=_(u"Estimated TAQ"), + required=False) + tpq = forms.IntegerField(label=_(u"TPQ"), required=False) + tpq_estimated = forms.IntegerField(label=_(u"Estimated TPQ"), + required=False) + + def __init__(self, *args, **kwargs): + super(RecordFormInterpretation, self).__init__(*args, **kwargs) + self.fields['activity'].choices = models.ActivityType.get_types() + self.fields['activity'].help_text = models.ActivityType.get_help() + self.fields['identification'].choices = \ + models.IdentificationType.get_types() + self.fields['identification'].help_text = \ + models.IdentificationType.get_help() + +record_search_wizard = SearchWizard([ + ('general-record_search', RecordFormSelection)], + url_name='record_search',) + +OperationRecordFormSelection = get_form_selection( + 'OperationRecordFormSelection', _(u"Operation search"), 'operation_id', + models.Operation, OperationSelect, 'get-operation', + _(u"You should select an operation.")) + + +record_creation_wizard = RecordWizard([ + ('selec-record_creation', OperationRecordFormSelection), + ('general-record_creation', RecordFormGeneral), + ('datings-record_creation', DatingFormSet), + ('interpretation-record_creation', RecordFormInterpretation), + ('final-record_creation', FinalForm)], + url_name='record_creation',) + +record_modification_wizard = RecordModifWizard([ + ('selec-record_modification', RecordFormSelection), + ('general-record_modification', RecordFormGeneral), + ('datings-record_modification', DatingFormSet), + ('interpretation-record_modification', RecordFormInterpretation), + ('final-record_modification', FinalForm)], + url_name='record_modification',) + +class RecordDeletionWizard(DeletionWizard): + model = models.ContextRecord + fields = ['label', 'parcel', 'description', 'length', 'width', 'thickness', + 'depth', 'location', 'datings', 'units', 'has_furniture', + 'filling', 'interpretation', 'taq', 'taq_estimated', 'tpq', + 'tpq_estimated'] + +class RecordDeletionForm(FinalForm): + confirm_msg = " " + confirm_end_msg = _(u"Would you like to delete this context record?") + +record_deletion_wizard = RecordDeletionWizard([ + ('selec-record_deletion', RecordFormSelection), + ('final-record_deletion', RecordDeletionForm)], + url_name='record_deletion',) + +######################################### +# Source management for context records # +######################################### + +class RecordSourceWizard(SourceWizard): + model = models.ContextRecordSource + +SourceRecordFormSelection = get_form_selection( + 'SourceRecordFormSelection', _(u"Context record search"), + 'context_record', models.ContextRecord, RecordSelect, 'get-contextrecord', + _(u"You should select a context record.")) + +record_source_creation_wizard = RecordSourceWizard([ + ('selec-record_source_creation', SourceRecordFormSelection), + ('source-record_source_creation', SourceForm), + ('authors-record_source_creation', AuthorFormset), + ('final-record_source_creation', FinalForm)], + url_name='record_source_creation',) + +class RecordSourceSelect(SourceSelect): + context_record__parcel__town = get_town_field( + label=_(u"Town of the operation")) + context_record__operation__year = forms.IntegerField( + label=_(u"Year of the operation")) + context_record__datings__period = forms.ChoiceField( + label=_(u"Period of the context record"), choices=[]) + context_record__unit = forms.ChoiceField( + label=_(u"Unit type of the context record"), choices=[]) + + def __init__(self, *args, **kwargs): + super(RecordSourceSelect, self).__init__(*args, **kwargs) + self.fields['context_record__datings__period'].choices = \ + models.Period.get_types() + self.fields['context_record__datings__period'].help_text = \ + models.Period.get_help() + self.fields['context_record__unit'].choices = models.Unit.get_types() + self.fields['context_record__unit'].help_text = models.Unit.get_help() + + +RecordSourceFormSelection = get_form_selection( + 'RecordSourceFormSelection', _(u"Documentation search"), 'pk', + models.ContextRecordSource, RecordSourceSelect, 'get-contextrecordsource', + _(u"You should select a document.")) + +record_source_modification_wizard = RecordSourceWizard([ + ('selec-record_source_modification', RecordSourceFormSelection), + ('source-record_source_modification', SourceForm), + ('authors-record_source_modification', AuthorFormset), + ('final-record_source_modification', FinalForm)], + url_name='record_source_modification',) + +class RecordSourceDeletionWizard(DeletionWizard): + model = models.ContextRecordSource + fields = ['context_record', 'title', 'source_type', 'authors',] + +record_source_deletion_wizard = RecordSourceDeletionWizard([ + ('selec-record_source_deletion', RecordSourceFormSelection), + ('final-record_source_deletion', RecordDeletionForm)], + url_name='record_source_deletion',) diff --git a/ishtar_common/forms_files.py b/ishtar_common/forms_files.py new file mode 100644 index 000000000..c4c460cee --- /dev/null +++ b/ishtar_common/forms_files.py @@ -0,0 +1,387 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Files forms definitions +""" +import datetime + +from django import forms +from django.shortcuts import render_to_response +from django.template import RequestContext +from django.core import validators +from django.core.exceptions import ObjectDoesNotExist +from django.db.models import Max +from django.utils.translation import ugettext_lazy as _ + +from ishtar import settings + +import models +import widgets +from forms import Wizard, FinalForm, FormSet, ClosingWizard, \ + ClosingDateFormSelection, SearchWizard, formset_factory, get_now, \ + reverse_lazy +from forms_common import TownFormset, ParcelFormSet, \ + get_town_field, get_person_field +from forms_operations import OperationAdministrativeActWizard, \ +AdministrativeActOpeForm, AdministrativeActOpeFormSelection, \ +AdministrativeActDeletionWizard, FinalAdministrativeActDeleteForm, is_preventive + +class FileWizard(Wizard): + model = models.File + object_parcel_type = 'associated_file' + + def get_form(self, request, storage, step=None, data=None, files=None): + """ + Manage towns + """ + if data: + data = data.copy() + else: + data = {} + # manage the dynamic choice of towns + if not step: + step = self.determine_step(request, storage) + form = self.get_form_list(request, storage)[step] + town_form_key = 'towns-' + self.url_name + if step.startswith('parcels-') and hasattr(form, 'management_form') \ + and self.session_has_key(request, storage, town_form_key): + towns = [] + qdict = request.session[storage.prefix]['step_data'][town_form_key] + for k in qdict.keys(): + if k.endswith("town") and qdict[k]: + try: + town = models.Town.objects.get(pk=int(qdict[k])) + towns.append((town.pk, unicode(town))) + except (ObjectDoesNotExist, ValueError): + pass + data['TOWNS'] = sorted(towns, key=lambda x:x[1]) + form = super(FileWizard, self).get_form(request, storage, step, data, + files) + return form + + def get_extra_model(self, dct, request, storage, form_list): + dct = super(FileWizard, self).get_extra_model(dct, request, storage, + form_list) + if not dct['numeric_reference']: + current_ref = models.File.objects.filter(year=dct['year'] + ).aggregate(Max('numeric_reference'))["numeric_reference__max"] + dct['numeric_reference'] = current_ref and current_ref + 1 or 1 + return dct + + def done(self, request, storage, form_list, **kwargs): + ''' + Save parcels + ''' + r = super(FileWizard, self).done(request, storage, form_list, + return_object=True, **kwargs) + if type(r) not in (list, tuple) or len(r) != 2: + return r + obj, res = r + obj.parcels.clear() + for form in form_list: + if not hasattr(form, 'prefix') \ + or not form.prefix.startswith('parcels-') \ + or not hasattr(form, 'forms'): + continue + for frm in form.forms: + if not frm.is_valid(): + continue + dct = frm.cleaned_data.copy() + if 'parcel' in dct: + try: + parcel = models.Parcel.objects.get(pk=dct['parcel']) + setattr(parcel, self.object_parcel_type, obj) + parcel.save() + except (ValueError, ObjectDoesNotExist): + continue + continue + try: + dct['town'] = models.Town.objects.get(pk=int(dct['town'])) + except (ValueError, ObjectDoesNotExist): + continue + dct['associated_file'], dct['operation'] = None, None + dct[self.object_parcel_type] = obj + if 'DELETE' in dct: + dct.pop('DELETE') + parcel = models.Parcel.objects.filter(**dct).count() + if not parcel: + dct['history_modifier'] = request.user + parcel = models.Parcel(**dct) + parcel.save() + return res + +class FileSelect(forms.Form): + towns = get_town_field() + in_charge = get_person_field(label=_(u"Person in charge"), + person_type='sra_agent') + file_type = forms.ChoiceField(label=_("File type"), + choices=models.FileType.get_types()) + saisine_type = forms.ChoiceField(label=_("Saisine type"), choices=[]) + year = forms.IntegerField(label=_("Year")) + + def __init__(self, *args, **kwargs): + super(FileSelect, self).__init__(*args, **kwargs) + self.fields['saisine_type'].choices = models.SaisineType.get_types() + self.fields['saisine_type'].help_text = models.SaisineType.get_help() + +class FileFormSelection(forms.Form): + form_label = _("Archaeological file search") + associated_models = {'pk':models.File} + currents = {'pk':models.File} + pk = forms.IntegerField(label="", required=False, + widget=widgets.JQueryJqGrid(reverse_lazy('get-file'), + FileSelect(), models.File, source_full=reverse_lazy('get-file-full')), + validators=[models.valid_id(models.File)]) + + def clean(self): + cleaned_data = self.cleaned_data + if 'pk' not in cleaned_data or not cleaned_data['pk']: + raise forms.ValidationError(_(u"You should select a file.")) + return cleaned_data + +class FileFormGeneral(forms.Form): + form_label = _("General") + associated_models = {'in_charge':models.Person, + 'related_file':models.File, + 'file_type':models.FileType} + in_charge = forms.IntegerField(label=_("Person in charge"), + widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person', + args=[models.PersonType.objects.get(txt_idx='sra_agent').pk]), + associated_model=models.Person, new=True), + validators=[models.valid_id(models.Person)]) + year = forms.IntegerField(label=_("Year"), + initial=lambda:datetime.datetime.now().year, + validators=[validators.MinValueValidator(1900), + validators.MaxValueValidator(2100)]) + numeric_reference = forms.IntegerField(label=_("Numeric reference"), + widget=forms.HiddenInput, required=False) + internal_reference = forms.CharField(label=_(u"Internal reference"), + max_length=60, + validators=[models.is_unique(models.File, 'internal_reference')]) + creation_date = forms.DateField(label=_(u"Creation date"), + initial=get_now, widget=widgets.JQueryDate) + file_type = forms.ChoiceField(label=_("File type"), + choices=models.FileType.get_types()) + related_file = forms.IntegerField(label=_("Related file"), required=False, + widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-file'), + associated_model=models.File), + validators=[models.valid_id(models.File)]) + comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea, + required=False) + +class FileFormGeneralRO(FileFormGeneral): + year = forms.IntegerField(label=_(u"Year"), + widget=forms.TextInput(attrs={'readonly':True})) + numeric_reference = forms.IntegerField(label=_(u"Numeric reference"), + widget=forms.TextInput(attrs={'readonly':True})) + internal_reference = forms.CharField(label=_(u"Internal reference"), + widget=forms.TextInput(attrs={'readonly':True},)) + +class FileFormAddress(forms.Form): + form_label = _(u"Address") + associated_models = {'town':models.Town} + total_surface = forms.IntegerField(required=False, + widget=widgets.AreaWidget, + label=_(u"Total surface (m²)"), + validators=[validators.MinValueValidator(0), + validators.MaxValueValidator(999999999)]) + address = forms.CharField(label=_(u"Main address"), widget=forms.Textarea) + address_complement = forms.CharField(label=_(u"Main address - complement"), + required=False) + postal_code = forms.CharField(label=_(u"Main address - postal code"), + max_length=10) + +class FileFormPreventive(forms.Form): + form_label = _(u"Preventive informations") + associated_models = {'general_contractor':models.Person, + 'saisine_type':models.SaisineType, + 'permit_type':models.PermitType, + 'town_planning_service':models.Organization} + general_contractor = forms.IntegerField(label=_(u"General contractor"), + widget=widgets.JQueryAutoComplete( + reverse_lazy('autocomplete-person', + args=[models.PersonType.objects.get(txt_idx='general_contractor').pk]), + associated_model=models.Person, new=True), + validators=[models.valid_id(models.Person)]) + town_planning_service = forms.IntegerField(required=False, + label=_(u"Town planning service"), + widget=widgets.JQueryAutoComplete( + reverse_lazy('autocomplete-organization', + args=[models.OrganizationType.objects.get(txt_idx='planning_service').pk]), + associated_model=models.Organization, new=True), + validators=[models.valid_id(models.Organization)]) + permit_type = forms.ChoiceField(label=_(u"Permit type"), required=False, + choices=models.PermitType.get_types()) + permit_reference = forms.CharField(label=_(u"Permit reference"), + required=False, validators=[validators.MaxLengthValidator(60)]) + total_developed_surface = forms.IntegerField(widget=widgets.AreaWidget, + label=_(u"Total developed surface (m²)"), + required=False, validators=[validators.MinValueValidator(0), + validators.MaxValueValidator(999999999)]) + if settings.COUNTRY == 'fr': + saisine_type = forms.ChoiceField(label=_(u"Saisine type"), + choices=[]) + reception_date = forms.DateField(label=_(u"Reception date"), + initial=get_now, widget=widgets.JQueryDate) + def __init__(self, *args, **kwargs): + super(FileFormPreventive, self).__init__(*args, **kwargs) + self.fields['saisine_type'].choices = models.SaisineType.get_types() + self.fields['saisine_type'].help_text = models.SaisineType.get_help() + +file_search_wizard = SearchWizard([('general-file_search', FileFormSelection)], + url_name='file_search',) + +file_creation_wizard = FileWizard([ + ('general-file_creation', FileFormGeneral), + ('address-file_creation', FileFormAddress), + ('towns-file_creation', TownFormset), + ('parcels-file_creation', ParcelFormSet), + ('preventive-file_creation', FileFormPreventive), + ('final-file_creation', FinalForm)], + condition_list={ +'preventive-file_creation':is_preventive('general-file_creation', + models.FileType, type_key='file_type') + }, + url_name='file_creation',) + +class FileModificationWizard(FileWizard): + modification = True + +file_modification_wizard = FileModificationWizard([ + ('selec-file_modification', FileFormSelection), + ('general-file_modification', FileFormGeneralRO), + ('adress-file_modification', FileFormAddress), + ('towns-file_modification', TownFormset), + ('parcels-file_modification', ParcelFormSet), + ('preventive-file_modification', FileFormPreventive), + ('final-file_modification', FinalForm)], + condition_list={ +'preventive-file_modification':is_preventive('general-file_modification', + models.FileType, type_key='file_type') + }, + url_name='file_modification',) + +class FileClosingWizard(ClosingWizard): + model = models.File + fields = ['year', 'numeric_reference', 'internal_reference', + 'file_type', 'in_charge', 'general_contractor', 'creation_date', + 'reception_date', 'total_surface', 'total_developed_surface', + 'address', 'address_complement', 'postal_code', 'comment'] + if settings.COUNTRY == 'fr': + fields += ['saisine_type', 'reference_number'] + fields += ['towns'] + +class FinalFileClosingForm(FinalForm): + confirm_msg = " " + confirm_end_msg = _(u"Would you like to close this archaeological file?") + +file_closing_wizard = FileClosingWizard([ + ('selec-file_closing', FileFormSelection), + ('date-file_closing', ClosingDateFormSelection), + ('final-file_closing', FinalFileClosingForm)], + url_name='file_closing',) + +class FileDeletionWizard(FileClosingWizard): + def get_formated_datas(self, forms): + datas = super(FileDeletionWizard, self).get_formated_datas(forms) + datas.append((_("Associated operations"), [])) + for operation in models.Operation.objects.filter( + associated_file=self.current_obj).all(): + if operation.end_date: + datas[-1][1].append(('', unicode(operation))) + return datas + + def done(self, request, storage, form_list, **kwargs): + obj = self.get_current_object(request, storage) + for operation in models.Operation.objects.filter( + associated_file=obj).all(): + operation.delete() + obj.delete() + return render_to_response('wizard_done.html', {}, + context_instance=RequestContext(request)) + + +class FinalFileDeleteForm(FinalForm): + confirm_msg = " " + confirm_end_msg = _(u"Would you like to delete this archaelogical file ?") + +file_deletion_wizard = FileDeletionWizard([ + ('selec-file_deletion', FileFormSelection), + ('final-file_deletion', FinalFileDeleteForm)], + url_name='file_deletion',) + +class FileAdministrativeActWizard(OperationAdministrativeActWizard): + model = models.File + +class FileEditAdministrativeActWizard(FileAdministrativeActWizard): + model = models.AdministrativeAct + edit = True + def get_associated_item(self, request, storage, dct): + return self.get_current_object(request, storage).associated_file + +class AdministrativeActFileSelect(forms.Form): + associated_file__towns = get_town_field() + act_type = forms.ChoiceField(label=_("Act type"), choices=[]) + + def __init__(self, *args, **kwargs): + super(AdministrativeActFileSelect, self).__init__(*args, **kwargs) + self.fields['act_type'].choices = models.ActType.get_types( + dct={'intented_to':'F'}) + self.fields['act_type'].help_text = models.ActType.get_help( + dct={'intented_to':'F'}) + +class AdministrativeActFileFormSelection(AdministrativeActOpeFormSelection): + pk = forms.IntegerField(label="", required=False, + widget=widgets.JQueryJqGrid(reverse_lazy('get-administrativeactfile'), + AdministrativeActFileSelect(), models.AdministrativeAct, + table_cols='TABLE_COLS_FILE'), + validators=[models.valid_id(models.AdministrativeAct)]) + +class AdministrativeActFileForm(AdministrativeActOpeForm): + act_type = forms.ChoiceField(label=_(u"Act type"), choices=[]) + + def __init__(self, *args, **kwargs): + super(AdministrativeActFileForm, self).__init__(*args, **kwargs) + self.fields['act_type'].choices = models.ActType.get_types( + dct={'intented_to':'F'}) + self.fields['act_type'].help_text = models.ActType.get_help( + dct={'intented_to':'F'}) + +file_administrativeactfile_wizard = FileAdministrativeActWizard([ + ('selec-file_administrativeactfile', FileFormSelection), + ('administrativeact-file_administrativeactfile', AdministrativeActFileForm), + ('final-file_administrativeactfile', FinalForm)], + url_name='file_administrativeactfile',) + +file_administrativeactfile_modification_wizard = FileEditAdministrativeActWizard([ + ('selec-file_administrativeactfile_modification', + AdministrativeActFileFormSelection), + ('administrativeact-file_administrativeactfile_modification', + AdministrativeActFileForm), + ('final-file_administrativeactfile_modification', FinalForm)], + url_name='file_administrativeactfile_modification',) + +file_administrativeactfile_deletion_wizard = AdministrativeActDeletionWizard([ + ('selec-file_administrativeactfile_deletion', + AdministrativeActFileFormSelection), + ('final-file_administrativeactfile_deletion', + FinalAdministrativeActDeleteForm)], + url_name='file_administrativeactfile_deletion',) + diff --git a/ishtar_common/forms_items.py b/ishtar_common/forms_items.py new file mode 100644 index 000000000..b763d94b2 --- /dev/null +++ b/ishtar_common/forms_items.py @@ -0,0 +1,525 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Items forms definitions +""" +import datetime + +from django import forms +from django.shortcuts import render_to_response +from django.template import RequestContext +from django.core import validators +from django.core.exceptions import ObjectDoesNotExist +from django.utils.safestring import mark_safe +from django.db.models import Max +from django.utils.translation import ugettext_lazy as _ + +from ishtar import settings + +import models +import widgets +from forms import Wizard, FinalForm, FormSet, SearchWizard, DeletionWizard,\ + FloatField, formset_factory, get_now, get_form_selection, reverse_lazy +from forms_common import get_town_field, get_warehouse_field, SourceForm, \ + SourceWizard, SourceSelect, SourceDeletionForm, AuthorFormset +from forms_context_records import RecordFormSelection + +class ItemWizard(Wizard): + model = models.Item + + def get_current_contextrecord(self, request, storage): + step = storage.get_current_step() + if not step: + return + if step.endswith('_creation'): # a context record has been selected + main_form_key = 'selecrecord-' + self.url_name + try: + idx = int(self.session_get_value(request, storage, + main_form_key, 'pk')) + current_cr = models.ContextRecord.objects.get(pk=idx) + return current_cr + except(TypeError, ValueError, ObjectDoesNotExist): + pass + current_item = self.get_current_object(request, storage) + if current_item: + base_items = current_item.base_items.all() + if base_items: + return base_items[0].context_record + + def get_template_context(self, request, storage, form=None): + """ + Get the operation and context record "reminder" on top of wizard forms + """ + context = super(ItemWizard, self).get_template_context(request, + storage, form) + current_cr = self.get_current_contextrecord(request, storage) + if not current_cr: + return context + operation = current_cr.operation + items = [] + if hasattr(operation, 'code_patriarche') and operation.code_patriarche: + items.append(unicode(operation.code_patriarche)) + items.append("-".join((unicode(operation.year), + unicode(operation.operation_code)))) + reminder = unicode(_("Current operation: ")) + u" - ".join(items) + reminder += u"<br/>" + unicode(_("Current context record: "))\ + + unicode(current_cr.label) + context['reminder'] = mark_safe(reminder) + return context + + def get_extra_model(self, dct, request, storage, form_list): + dct = super(ItemWizard, self).get_extra_model(dct, request, storage, + form_list) + dct['order'] = 1 + if 'pk' in dct and type(dct['pk']) == models.ContextRecord: + dct['base_items__context_record'] = dct.pop('pk') + return dct + +class ItemForm(forms.Form): + form_label = _("Item") + base_model = 'base_items' + associated_models = {'material_type':models.MaterialType,} + label = forms.CharField(label=_(u"ID"), + validators=[validators.MaxLengthValidator(60)]) + description = forms.CharField(label=_("Description"), + widget=forms.Textarea) + base_items__is_isolated = forms.NullBooleanField(label=_(u"Is isolated?"), + required=False) + material_type = forms.ChoiceField(label=_("Material type"), + choices=models.MaterialType.get_types()) + volume = FloatField(label=_(u"Volume (l)"), required=False) + weight = FloatField(label=_(u"Weight (g)"), required=False) + item_number = forms.IntegerField(label=_(u"Item number"), required=False) + +class DateForm(forms.Form): + form_label = _("Dating") + base_model = 'dating' + associated_models = {'dating__dating_type':models.DatingType, + 'dating__quality':models.DatingQuality, + 'dating__period':models.Period} + dating__period = forms.ChoiceField(label=_("Period"), + choices=models.Period.get_types()) + dating__start_date = forms.IntegerField(label=_(u"Start date"), + required=False) + dating__end_date = forms.IntegerField(label=_(u"End date"), required=False) + dating__quality = forms.ChoiceField(label=_("Quality"), required=False, + choices=models.DatingQuality.get_types()) + dating__dating_type = forms.ChoiceField(label=_("Dating type"), + required=False, choices=[]) + + def __init__(self, *args, **kwargs): + super(DateForm, self).__init__(*args, **kwargs) + self.fields['dating__dating_type'].choices = models.DatingType.get_types() + self.fields['dating__dating_type'].help_text = models.DatingType.get_help() + +item_creation_wizard = ItemWizard([ + ('selecrecord-item_creation', RecordFormSelection), + ('item-item_creation', ItemForm), + ('dating-item_creation', DateForm), + ('final-item_creation', FinalForm)], + url_name='item_creation',) + +class ItemSelect(forms.Form): + base_items__context_record__parcel__town = get_town_field() + base_items__context_record__operation__year = forms.IntegerField( + label=_(u"Year")) + base_items__context_record__operation__code_patriarche = \ + forms.IntegerField(label=_(u"Code PATRIARCHE")) + dating__period = forms.ChoiceField(label=_(u"Period"), choices=[]) + # TODO search by warehouse + material_type = forms.ChoiceField(label=_(u"Material type"), choices=[]) + base_items__item__description = forms.CharField(label=_(u"Description")) + base_items__is_isolated = forms.NullBooleanField(label=_(u"Is isolated?")) + + def __init__(self, *args, **kwargs): + super(ItemSelect, self).__init__(*args, **kwargs) + self.fields['dating__period'].choices = \ + models.Period.get_types() + self.fields['dating__period'].help_text = \ + models.Period.get_help() + self.fields['material_type'].choices = \ + models.MaterialType.get_types() + self.fields['material_type'].help_text = \ + models.MaterialType.get_help() + +class ItemFormSelection(forms.Form): + form_label = _("Item search") + associated_models = {'pk':models.Item} + currents = {'pk':models.Item} + pk = forms.IntegerField(label="", required=False, + widget=widgets.JQueryJqGrid(reverse_lazy('get-item'), + ItemSelect(), models.Item, source_full=reverse_lazy('get-item-full')), + validators=[models.valid_id(models.Item)]) + +item_search_wizard = SearchWizard([ + ('general-item_search', ItemFormSelection)], + url_name='item_search',) + +class ItemModificationWizard(ItemWizard): + modification = True + +item_modification_wizard = ItemModificationWizard([ + ('selec-item_modification', ItemFormSelection), + ('item-item_modification', ItemForm), + ('dating-item_modification', DateForm), + ('final-item_modification', FinalForm)], + url_name='item_modification',) + +class TreatmentWizard(Wizard): + model = models.Treatment + +class BaseTreatmentForm(forms.Form): + form_label = _(u"Base treatment") + associated_models = {'treatment_type':models.TreatmentType, + 'person':models.Person, + 'location':models.Warehouse} + treatment_type = forms.ChoiceField(label=_(u"Treatment type"), choices=[]) + person = forms.IntegerField(label=_(u"Person"), + widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person'), + associated_model=models.Person, new=True), + validators=[models.valid_id(models.Person)]) + location = forms.IntegerField(label=_(u"Location"), + widget=widgets.JQueryAutoComplete( + reverse_lazy('autocomplete-warehouse'), associated_model=models.Warehouse, + new=True), + validators=[models.valid_id(models.Warehouse)]) + description = forms.CharField(label=_(u"Description"), + widget=forms.Textarea, required=False) + start_date = forms.DateField(label=_(u"Start date"), required=False, + widget=widgets.JQueryDate) + end_date = forms.DateField(label=_(u"End date"), required=False, + widget=widgets.JQueryDate) + + def __init__(self, *args, **kwargs): + super(BaseTreatmentForm, self).__init__(*args, **kwargs) + self.fields['treatment_type'].choices = models.TreatmentType.get_types( + exclude=['packaging']) + self.fields['treatment_type'].help_text = models.TreatmentType.get_help( + exclude=['packaging']) + +class ItemMultipleFormSelection(forms.Form): + form_label = _(u"Upstream items") + associated_models = {'items':models.Item} + associated_labels = {'items':_(u"Items")} + items = forms.CharField(label="", required=False, + widget=widgets.JQueryJqGrid(reverse_lazy('get-item'), + ItemSelect(), models.Item, multiple=True, multiple_cols=[2, 3, 4]), + validators=[models.valid_ids(models.Item)]) + + def clean(self): + if not 'items' in self.cleaned_data or not self.cleaned_data['items']: + raise forms.ValidationError(_(u"You should at least select one " + u"archaeological item.")) + return self.cleaned_data + +class ContainerForm(forms.Form): + form_label = _(u"Container") + reference = forms.CharField(label=_(u"Reference")) + container_type = forms.ChoiceField(label=_(u"Container type"), choices=[]) + location = forms.IntegerField(label=_(u"Warehouse"), + widget=widgets.JQueryAutoComplete( + reverse_lazy('autocomplete-warehouse'), associated_model=models.Warehouse, + new=True), + validators=[models.valid_id(models.Warehouse)]) + comment = forms.CharField(label=_(u"Comment"), + widget=forms.Textarea, required=False) + + def __init__(self, *args, **kwargs): + super(ContainerForm, self).__init__(*args, **kwargs) + self.fields['container_type'].choices = \ + models.ContainerType.get_types() + self.fields['container_type'].help_text = \ + models.ContainerType.get_help() + + def save(self, user): + dct = self.cleaned_data + dct['history_modifier'] = user + dct['container_type'] = models.ContainerType.objects.get( + pk=dct['container_type']) + dct['location'] = models.Warehouse.objects.get(pk=dct['location']) + new_item = models.Container(**dct) + new_item.save() + return new_item + +def check_treatment(form_name, type_key, type_list=[], not_type_list=[]): + type_list = [models.TreatmentType.objects.get(txt_idx=tpe).pk + for tpe in type_list] + not_type_list = [models.TreatmentType.objects.get(txt_idx=tpe).pk + for tpe in not_type_list] + def func(self, request, storage): + if storage.prefix not in request.session or \ + 'step_data' not in request.session[storage.prefix] or \ + form_name not in request.session[storage.prefix]['step_data'] or\ + form_name + '-' + type_key not in \ + request.session[storage.prefix]['step_data'][form_name]: + return False + try: + type = int(request.session[storage.prefix]['step_data']\ + [form_name][form_name+'-'+type_key]) + return (not type_list or type in type_list) \ + and type not in not_type_list + except ValueError: + return False + return func + +class ResultItemForm(forms.Form): + form_label = _(u"Resulting item") + associated_models = {'material_type':models.MaterialType} + label = forms.CharField(label=_(u"ID"), + validators=[validators.MaxLengthValidator(60)]) + description = forms.CharField(label=_(u"Precise description"), + widget=forms.Textarea) + material_type = forms.ChoiceField(label=_(u"Material type"), + choices=models.MaterialType.get_types()) + volume = forms.IntegerField(label=_(u"Volume (l)")) + weight = forms.IntegerField(label=_(u"Weight (g)")) + item_number = forms.IntegerField(label=_(u"Item number")) + +ResultItemFormSet = formset_factory(ResultItemForm, can_delete=True, + formset=FormSet) +ResultItemFormSet.form_label = _(u"Resulting items") + +class UpstreamItemFormSelection(ItemFormSelection): + form_label = _(u"Upstream item") + +treatment_creation_wizard = TreatmentWizard([ + ('basetreatment-treatment_creation', BaseTreatmentForm), + ('selecitem-treatment_creation', UpstreamItemFormSelection), + ('multiselecitems-treatment_creation', ItemMultipleFormSelection), + ('container-treatment_creation', ContainerForm), + ('resultitem-treatment_creation', ResultItemForm), + ('resultitems-treatment_creation', ResultItemFormSet), + ('final-treatment_creation', FinalForm)], + condition_list={ +'selecitem-treatment_creation': + check_treatment('basetreatment-treatment_creation', 'treatment_type', + not_type_list=['physical_grouping', 'packaging']), +'multiselecitems-treatment_creation': + check_treatment('basetreatment-treatment_creation', 'treatment_type', + ['physical_grouping', 'packaging']), +'resultitems-treatment_creation': + check_treatment('basetreatment-treatment_creation', 'treatment_type', + ['split']), +'resultitem-treatment_creation': + check_treatment('basetreatment-treatment_creation', 'treatment_type', + not_type_list=['split']), +'container-treatment_creation': + check_treatment('basetreatment-treatment_creation', 'treatment_type', + ['packaging']), + }, + url_name='treatment_creation',) + +############# +# Packaging # +############# + +class PackagingWizard(TreatmentWizard): + def save_model(self, dct, m2m, whole_associated_models, request, storage, + form_list, return_object): + dct = self.get_extra_model(dct, request, storage, form_list) + obj = self.get_current_saved_object(request, storage) + dct['location'] = dct['container'].location + items = dct.pop('items') + treatment = models.Treatment(**dct) + treatment.save() + if not hasattr(items, '__iter__'): + items = [items] + for item in items: + new = item.duplicate(request.user) + item.downstream_treatment = treatment + item.save() + new.upstream_treatment = treatment + new.container = dct['container'] + new.save() + res = render_to_response('wizard_done.html', {}, + context_instance=RequestContext(request)) + return return_object and (obj, res) or res + +class ContainerSelect(forms.Form): + location = get_warehouse_field() + container_type = forms.ChoiceField(label=_(u"Container type"), choices=[]) + reference = forms.CharField(label=_(u"Reference")) + + def __init__(self, *args, **kwargs): + super(ContainerSelect, self).__init__(*args, **kwargs) + self.fields['container_type'].choices = \ + models.ContainerType.get_types() + self.fields['container_type'].help_text = \ + models.ContainerType.get_help() + +ContainerFormSelection = get_form_selection( + 'ContainerFormSelection', _(u"Container search"), 'container', + models.Container, ContainerSelect, 'get-container', + _(u"You should select a container."), new=True, + new_message=_(u"Add a new container")) + +class BasePackagingForm(forms.Form): + form_label = _(u"Packaging") + associated_models = {'treatment_type':models.TreatmentType, + 'person':models.Person, + 'location':models.Warehouse} + treatment_type = forms.IntegerField(label="", widget=forms.HiddenInput) + person = forms.IntegerField(label=_(u"Packager"), + widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person'), + associated_model=models.Person, new=True), + validators=[models.valid_id(models.Person)]) + start_date = forms.DateField(label=_(u"Date"), required=False, + widget=widgets.JQueryDate) + + def __init__(self, *args, **kwargs): + super(BasePackagingForm, self).__init__(*args, **kwargs) + self.fields['treatment_type'].initial = \ + models.TreatmentType.objects.get(txt_idx='packaging').pk + +class ItemPackagingFormSelection(ItemMultipleFormSelection): + form_label = _(u"Packaged items") + +warehouse_packaging_wizard = PackagingWizard([ + ('seleccontainer-packaging', ContainerFormSelection), + ('base-packaging', BasePackagingForm), + ('multiselecitems-packaging', ItemPackagingFormSelection), + ('final-packaging', FinalForm)], + url_name='warehouse_packaging',) + +""" +warehouse_packaging_wizard = ItemSourceWizard([ + ('selec-warehouse_packaging', ItemsSelection), + ('final-warehouse_packaging', FinalForm)], + url_name='warehouse_packaging',) +""" +############################################# +# Source management for archaelogical items # +############################################# + +class ItemSourceWizard(SourceWizard): + model = models.ItemSource + +SourceItemFormSelection = get_form_selection( + 'SourceItemFormSelection', _(u"Archaelogical item search"), 'item', + models.Item, ItemSelect, 'get-item', + _(u"You should select an archaelogical item.")) + +item_source_creation_wizard = ItemSourceWizard([ + ('selec-item_source_creation', SourceItemFormSelection), + ('source-item_source_creation', SourceForm), + ('authors-item_source_creation', AuthorFormset), + ('final-item_source_creation', FinalForm)], + url_name='item_source_creation',) + +class ItemSourceSelect(SourceSelect): + item__base_items__context_record__operation__year = forms.IntegerField( + label=_(u"Year of the operation")) + item__dating__period = forms.ChoiceField( + label=_(u"Period of the archaelogical item"), + choices=[]) + item__material_type = forms.ChoiceField( + label=_("Material type of the archaelogical item"), + choices=models.MaterialType.get_types()) + item__description = forms.CharField( + label=_(u"Description of the archaelogical item")) + + def __init__(self, *args, **kwargs): + super(ItemSourceSelect, self).__init__(*args, **kwargs) + self.fields['item__dating__period'].choices = \ + models.Period.get_types() + self.fields['item__dating__period'].help_text = \ + models.Period.get_help() + self.fields['item__material_type'].choices = \ + models.MaterialType.get_types() + self.fields['item__material_type'].help_text = \ + models.MaterialType.get_help() + +ItemSourceFormSelection = get_form_selection( + 'ItemSourceFormSelection', _(u"Documentation search"), 'pk', + models.ItemSource, ItemSourceSelect, 'get-itemsource', + _(u"You should select a document.")) + +item_source_modification_wizard = ItemSourceWizard([ + ('selec-item_source_modification', ItemSourceFormSelection), + ('source-item_source_modification', SourceForm), + ('authors-item_source_modification', AuthorFormset), + ('final-item_source_modification', FinalForm)], + url_name='item_source_modification',) + +class ItemSourceDeletionWizard(DeletionWizard): + model = models.ItemSource + fields = ['item', 'title', 'source_type', 'authors',] + +item_source_deletion_wizard = ItemSourceDeletionWizard([ + ('selec-item_source_deletion', ItemSourceFormSelection), + ('final-item_source_deletion', SourceDeletionForm)], + url_name='item_source_deletion',) + +""" + +#################################### +# Source management for treatments # +#################################### + +class TreatmentSourceWizard(SourceWizard): + model = models.TreamentSource + +SourceTreatementFormSelection = get_form_selection( + 'SourceTreatmentFormSelection', _(u"Treatment search"), 'operation', + models.Treatment, TreatmentSelect, 'get-treatment', + _(u"You should select a treatment.")) + +treatment_source_creation_wizard = TreatmentSourceWizard([ + ('selec-treatment_source_creation', SourceTreatmentFormSelection), + ('source-treatment_source_creation', SourceForm), + ('authors-treatment_source_creation', AuthorFormset), + ('final-treatment_source_creation', FinalForm)], + url_name='treatment_source_creation',) + +class TreatmentSourceSelect(SourceSelect): + operation__towns = get_town_field(label=_(u"Operation's town")) + treatment__treatment_type = forms.ChoiceField(label=_(u"Operation type"), + choices=[]) + operation__year = forms.IntegerField(label=_(u"Operation's year")) + + def __init__(self, *args, **kwargs): + super(OperationSourceSelect, self).__init__(*args, **kwargs) + self.fields['operation__operation_type'].choices = \ + models.OperationType.get_types() + self.fields['operation__operation_type'].help_text = \ + models.OperationType.get_help() + + +OperationSourceFormSelection = get_form_selection( + 'OperationSourceFormSelection', _(u"Documentation search"), 'pk', + models.OperationSource, OperationSourceSelect, 'get-operationsource', + _(u"You should select a document.")) + +operation_source_modification_wizard = OperationSourceWizard([ + ('selec-operation_source_modification', OperationSourceFormSelection), + ('source-operation_source_modification', SourceForm), + ('authors-operation_source_modification', AuthorFormset), + ('final-operation_source_modification', FinalForm)], + url_name='operation_source_modification',) + +class OperationSourceDeletionWizard(DeletionWizard): + model = models.OperationSource + fields = ['operation', 'title', 'source_type', 'authors',] + +operation_source_deletion_wizard = OperationSourceDeletionWizard([ + ('selec-operation_source_deletion', OperationSourceFormSelection), + ('final-operation_source_deletion', SourceDeletionForm)], + url_name='operation_source_deletion',) +""" diff --git a/ishtar_common/forms_main.py b/ishtar_common/forms_main.py new file mode 100644 index 000000000..29253f284 --- /dev/null +++ b/ishtar_common/forms_main.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +from forms_common import * +#from forms_files import * +#from forms_operations import * +#from forms_context_records import * +#from forms_items import * +from forms import * + diff --git a/ishtar_common/forms_operations.py b/ishtar_common/forms_operations.py new file mode 100644 index 000000000..e163b5869 --- /dev/null +++ b/ishtar_common/forms_operations.py @@ -0,0 +1,754 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Operations forms definitions +""" +import datetime + +from django import forms +from django.shortcuts import render_to_response +from django.template import RequestContext +from django.core import validators +from django.core.exceptions import ObjectDoesNotExist +from django.db.models import Max +from django.utils.translation import ugettext_lazy as _ + +from ishtar import settings + +import models +import widgets +from forms import Wizard, FinalForm, FormSet, SearchWizard, ClosingWizard, \ + ClosingDateFormSelection, DeletionWizard, formset_factory, get_now, \ + reverse_lazy, get_form_selection +from forms_common import TownForm, TownFormSet, TownFormset, ParcelFormSet, \ + ParcelForm, AuthorFormset, SourceForm, SourceWizard, SourceSelect, \ + SourceDeletionForm, get_town_field + +def is_preventive(form_name, model, type_key='operation_type', key=''): + def func(self, request, storage): + if storage.prefix not in request.session or \ + 'step_data' not in request.session[storage.prefix] or \ + form_name not in request.session[storage.prefix]['step_data'] or\ + form_name + '-' + type_key not in \ + request.session[storage.prefix]['step_data'][form_name]: + return False + try: + typ = int(request.session[storage.prefix]['step_data']\ + [form_name][form_name+'-'+type_key]) + return model.is_preventive(typ, key) + except ValueError: + return False + return func + +class OperationWizard(Wizard): + model = models.Operation + object_parcel_type = 'operation' + + def get_template(self, request, storage): + templates = super(OperationWizard, self).get_template(request, storage) + current_step = storage.get_current_step() or self.get_first_step( + request, storage) + if current_step.startswith('towns-'): + templates = ['towns_wizard.html'] + templates + return templates + + def get_extra_context(self, request, storage): + """ + Return extra context for templates + """ + context = super(OperationWizard, self).get_extra_context(request, + storage) + step = self.determine_step(request, storage) + if not step.startswith('towns-'): + return context + context['TOWNS'] = self.get_towns(request, storage) + return context + + def get_towns(self, request, storage): + """ + Obtention des villes disponibles + """ + general_form_key = 'general-' + self.url_name + towns = [] + file_id = self.session_get_value(request, storage, general_form_key, + "associated_file") + if file_id: + try: + for town in models.File.objects.get(pk=int(file_id) + ).towns.all(): + towns.append((town.pk, unicode(town))) + except (ValueError, ObjectDoesNotExist): + pass + return sorted(towns, key=lambda x:x[1]) + else: + return -1 + + def get_form(self, request, storage, step=None, data=None, files=None): + """ + Manage specifics fields + """ + if data: + data = data.copy() + else: + data = {} + if not step: + step = self.determine_step(request, storage) + form = self.get_form_list(request, storage)[step] + general_form_key = 'general-' + self.url_name + # manage the dynamic choice of towns + if step.startswith('towns-') and hasattr(form, 'management_form'): + data['TOWNS'] = self.get_towns(request, storage) + elif step.startswith('parcels') and hasattr(form, 'management_form'): + file_id = self.session_get_value(request, storage, general_form_key, + "associated_file") + if file_id: + parcels = [] + try: + for parcel in models.File.objects.get(pk=int(file_id) + ).parcels.all(): + parcels.append((parcel.pk, parcel.short_label())) + except (ValueError, ObjectDoesNotExist): + pass + data['PARCELS'] = sorted(parcels, key=lambda x:x[1]) + else: + town_form_key = step.startswith('parcelsgeneral') \ + and 'townsgeneral-' or 'towns-' + town_form_key += self.url_name + town_ids = self.session_get_value(request, storage, + town_form_key, 'town', multi=True) or [] + towns = [] + for town_id in town_ids: + try: + town = models.Town.objects.get(pk=int(town_id)) + towns.append((town.pk, unicode(town))) + except (ValueError, ObjectDoesNotExist): + pass + data['TOWNS'] = sorted(towns, key=lambda x:x[1]) + data = data or None + form = super(OperationWizard, self).get_form(request, storage, step, + data, files) + return form + + def get_formated_datas(self, forms): + """ + Show a specific warning if no archaelogical file is provided + """ + datas = super(OperationWizard, self).get_formated_datas(forms) + # if the general town form is used the advertissement is pertinent + has_no_af = [form.prefix for form in forms + if form.prefix == 'townsgeneral-operation'] and True + if has_no_af: + datas = [[_(u"Warning: No Archaelogical File is provided. " + u"If you have forget it return to the first step."), []]]\ + + datas + return datas + +class OperationSelect(forms.Form): + common_name = forms.CharField(label=_(u"Name"), max_length=30) + towns = get_town_field() + operation_type = forms.ChoiceField(label=_(u"Operation type"), + choices=[]) + remains = forms.ChoiceField(label=_(u"Remains"), + choices=models.RemainType.get_types()) + year = forms.IntegerField(label=_("Year")) + end_date = forms.NullBooleanField(label=_(u"Is open?")) + + def __init__(self, *args, **kwargs): + super(OperationSelect, self).__init__(*args, **kwargs) + self.fields['operation_type'].choices = models.OperationType.get_types() + self.fields['operation_type'].help_text = models.OperationType.get_help() + +class OperationFormSelection(forms.Form): + form_label = _(u"Operation search") + associated_models = {'pk':models.Operation} + currents = {'pk':models.Operation} + pk = forms.IntegerField(label="", required=False, + widget=widgets.JQueryJqGrid(reverse_lazy('get-operation'), + OperationSelect(), models.Operation, + source_full=reverse_lazy('get-operation-full')), + validators=[models.valid_id(models.Operation)]) + + def clean(self): + cleaned_data = self.cleaned_data + if 'pk' not in cleaned_data or not cleaned_data['pk']: + raise forms.ValidationError(_(u"You should select an operation.")) + return cleaned_data + +class OperationCodeInput(forms.TextInput): + """Manage auto complete whene changing year in form""" + def render(self, *args, **kwargs): + name, value = args + base_name = '-'.join(name.split('-')[:-1]) + rendered = super(OperationCodeInput, self).render(*args, **kwargs) + js = u"""\n <script type="text/javascript"><!--// + function initialyse_operation_code () { + // if the form is in creation mode + if(!$("#id_%(base_name)s-pk").val()){ + $("#id_%(base_name)s-year").change(function() { + var year = $("#id_%(base_name)s-year").val(); + var url = "%(url)s" + year; + $.getJSON(url, function(data) { + $("#id_%(name)s").val(data.id); + }); + }); + } + } + $(document).ready(initialyse_operation_code()); + //--></script>\n""" % {'base_name':base_name, 'name':name, + 'url':reverse_lazy('get_available_operation_code')} + return rendered + js + +class OperationFormGeneral(forms.Form): + form_label = _(u"General") + associated_models = {'in_charge':models.Person, + 'associated_file':models.File, + 'operation_type':models.OperationType} + currents = {'associated_file':models.File} + pk = forms.IntegerField(required=False, widget=forms.HiddenInput) + in_charge = forms.IntegerField(label=_("Person in charge of the operation"), + widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person', + args=["_".join( + [unicode(models.PersonType.objects.get(txt_idx='head_scientist').pk), + unicode(models.PersonType.objects.get(txt_idx='sra_agent').pk)])]), + associated_model=models.Person, new=True), + validators=[models.valid_id(models.Person)], required=False) + associated_file = forms.IntegerField(label=_(u"Archaelogical file"), + widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-file'), + associated_model=models.File), + validators=[models.valid_id(models.File)], required=False) + operation_type = forms.ChoiceField(label=_(u"Operation type"), + choices=[]) + start_date = forms.DateField(label=_(u"Start date"), required=False, + widget=widgets.JQueryDate) + excavation_end_date = forms.DateField(label=_(u"Excavation end date"), + required=False, widget=widgets.JQueryDate) + surface = forms.IntegerField(required=False, widget=widgets.AreaWidget, + label=_(u"Total surface (m²)"), + validators=[validators.MinValueValidator(0), + validators.MaxValueValidator(999999999)]) + year = forms.IntegerField(label=_(u"Year"), + initial=lambda:datetime.datetime.now().year, + validators=[validators.MinValueValidator(1900), + validators.MaxValueValidator(2100)]) + operation_code = forms.IntegerField(label=_(u"Operation code"), + initial=models.Operation.get_available_operation_code, + widget=OperationCodeInput) + common_name = forms.CharField(label=_(u"Generic name"), required=False, + max_length=120, widget=forms.Textarea) + operator_reference = forms.CharField(label=_(u"Operator reference"), + required=False, max_length=20) + if settings.COUNTRY == 'fr': + code_patriarche = forms.IntegerField(label=u"Code PATRIARCHE", + required=False) + code_dracar = forms.CharField(label=u"Code DRACAR", required=False, + validators=[validators.MaxLengthValidator(10)]) + comment = forms.CharField(label=_(u"Comment"), widget=forms.Textarea, + required=False) + + def __init__(self, *args, **kwargs): + super(OperationFormGeneral, self).__init__(*args, **kwargs) + self.fields['operation_type'].choices = models.OperationType.get_types() + self.fields['operation_type'].help_text = models.OperationType.get_help() + + def clean(self): + cleaned_data = self.cleaned_data + # verify the logic between start date and excavation end date + if cleaned_data['excavation_end_date']: + if not self.cleaned_data['start_date']: + raise forms.ValidationError(_(u"If you want to set an " + u"excavation end date you have to provide a start date.")) + if cleaned_data['excavation_end_date'] < cleaned_data['start_date']: + raise forms.ValidationError(_(u"The excavation end date "\ + u"cannot be before the start date.")) + year = self.cleaned_data.get("year") + operation_code = cleaned_data.get("operation_code") + ops = models.Operation.objects.filter(year=year, + operation_code=operation_code) + # manage unique operation ID + if 'pk' in cleaned_data and cleaned_data['pk']: + ops = ops.exclude(pk=cleaned_data['pk']) + if ops.count(): + max_val = models.Operation.objects.filter(year=year).aggregate( + Max('operation_code'))["operation_code__max"] + raise forms.ValidationError(_(u"Operation code already exist for " + u"year: %(year)d - use a value bigger than %(last_val)d") % { + 'year':year, 'last_val':max_val}) + return self.cleaned_data + +class OperationFormPreventive(forms.Form): + form_label = _(u"Preventive informations - excavation") + cost = forms.IntegerField(label=_(u"Cost (€)"), required=False) + scheduled_man_days = forms.IntegerField(label=_(u"Scheduled man-days"), + required=False) + optional_man_days = forms.IntegerField(label=_(u"Optional man-days"), + required=False) + effective_man_days = forms.IntegerField(label=_(u"Effective man-days"), + required=False) + if settings.COUNTRY == 'fr': + fnap_financing = forms.FloatField(required=False, + label=u"Pourcentage de financement FNAP", + validators=[validators.MinValueValidator(0), + validators.MaxValueValidator(100)]) + +class OperationFormPreventiveDiag(forms.Form): + form_label = _("Preventive informations - diagnostic") + if settings.COUNTRY == 'fr': + zoning_prescription = forms.NullBooleanField(required=False, + label=_(u"Prescription on zoning")) + large_area_prescription = forms.NullBooleanField(required=False, + label=_(u"Prescription on large area")) + geoarchaeological_context_prescription = forms.NullBooleanField( + required=False, label=_(u"Prescription on geoarchaeological context")) + +class SelectedTownForm(forms.Form): + form_label = _("Towns") + associated_models = {'town':models.Town} + town = forms.ChoiceField(label=_("Town"), choices=(), + validators=[models.valid_id(models.Town)]) + def __init__(self, *args, **kwargs): + towns = None + if 'data' in kwargs and 'TOWNS' in kwargs['data']: + towns = kwargs['data']['TOWNS'] + # clean data if not "real" data + prefix_value = kwargs['prefix'] + '-town' + if not [k for k in kwargs['data'].keys() + if k.startswith(prefix_value) and kwargs['data'][k]]: + kwargs['data'] = None + if 'files' in kwargs: + kwargs.pop('files') + super(SelectedTownForm, self).__init__(*args, **kwargs) + if towns and towns != -1: + self.fields['town'].choices = [('', '--')] + towns + +SelectedTownFormset = formset_factory(SelectedTownForm, can_delete=True, + formset=TownFormSet) +SelectedTownFormset.form_label = _(u"Towns") + +class SelectedParcelForm(forms.Form): + form_label = _("Parcels") + associated_models = {'parcel':models.Parcel} + parcel = forms.ChoiceField(label=_("Parcel"), choices=(), + validators=[models.valid_id(models.Parcel)]) + def __init__(self, *args, **kwargs): + parcels = None + if 'data' in kwargs and 'PARCELS' in kwargs['data']: + parcels = kwargs['data']['PARCELS'] + # clean data if not "real" data + prefix_value = kwargs['prefix'] + '-parcel' + if not [k for k in kwargs['data'].keys() + if k.startswith(prefix_value) and kwargs['data'][k]]: + kwargs['data'] = None + if 'files' in kwargs: + kwargs.pop('files') + super(SelectedParcelForm, self).__init__(*args, **kwargs) + if parcels: + self.fields['parcel'].choices = [('', '--')] + parcels + +SelectedParcelFormSet = formset_factory(SelectedParcelForm, can_delete=True, + formset=ParcelFormSet) +SelectedParcelFormSet.form_label = _("Parcels") + +SelectedParcelGeneralFormSet = formset_factory(ParcelForm, can_delete=True, + formset=ParcelFormSet) +SelectedParcelGeneralFormSet.form_label = _("Parcels") + +class RemainForm(forms.Form): + form_label = _("Remain types") + base_model = 'remain' + associated_models = {'remain':models.RemainType} + remain = forms.ChoiceField(label=_("Remain type"), required=False, + choices=models.RemainType.get_types()) + +class RemainFormSet(FormSet): + def clean(self): + """Checks that no remain types are duplicated.""" + return self.check_duplicate(['remain_type'], + _(u"There are identical remain types")) + +RemainFormset = formset_factory(RemainForm, can_delete=True, + formset=RemainFormSet) +RemainFormset.form_label = _("Remain types") + +class PeriodForm(forms.Form): + form_label = _("Periods") + base_model = 'period' + associated_models = {'period':models.Period} + period = forms.ChoiceField(label=_("Period"), required=False, + choices=models.Period.get_types()) + +class PeriodFormSet(FormSet): + def clean(self): + """Checks that no period are duplicated.""" + return self.check_duplicate(['period'], + _(u"There are identical periods")) + +PeriodFormset = formset_factory(PeriodForm, can_delete=True, + formset=PeriodFormSet) +PeriodFormset.form_label = _("Periods") + +operation_search_wizard = SearchWizard([ + ('general-operation_search', OperationFormSelection)], + url_name='operation_search',) + +def has_associated_file(form_name, file_key='associated_file', negate=False): + def func(self, request, storage): + if storage.prefix not in request.session or \ + 'step_data' not in request.session[storage.prefix] or \ + form_name not in request.session[storage.prefix]['step_data'] or\ + form_name + '-' + file_key not in \ + request.session[storage.prefix]['step_data'][form_name]: + return negate + try: + file_id = int(request.session[storage.prefix]['step_data']\ + [form_name][form_name+'-'+file_key]) + return not negate + except ValueError: + return negate + return func + +operation_creation_wizard = OperationWizard([ + ('general-operation_creation', OperationFormGeneral), + ('preventive-operation_creation', OperationFormPreventive), + ('preventivediag-operation_creation', OperationFormPreventiveDiag), + ('townsgeneral-operation_creation', TownFormset), + ('towns-operation_creation', SelectedTownFormset), + ('parcelsgeneral-operation_creation', SelectedParcelGeneralFormSet), + ('parcels-operation_creation', SelectedParcelFormSet), + ('remains-operation_creation', RemainFormset), + ('periods-operation_creation', PeriodFormset), + ('final-operation_creation', FinalForm)], + condition_list={ +'preventive-operation_creation':is_preventive('general-operation_creation', + models.OperationType, 'operation_type', 'prev_excavation'), +'preventivediag-operation_creation':is_preventive('general-operation_creation', + models.OperationType, 'operation_type', 'arch_diagnostic'), +'townsgeneral-operation_creation':has_associated_file( + 'general-operation_creation', negate=True), +'towns-operation_creation':has_associated_file('general-operation_creation'), +'parcelsgeneral-operation_creation':has_associated_file( + 'general-operation_creation', negate=True), +'parcels-operation_creation':has_associated_file('general-operation_creation'), + }, + url_name='operation_creation',) + +class OperationModificationWizard(OperationWizard): + modification = True + +operation_modification_wizard = OperationModificationWizard([ + ('selec-operation_modification', OperationFormSelection), + ('general-operation_modification', OperationFormGeneral), + ('preventive-operation_modification', OperationFormPreventive), + ('preventivediag-operation_modification', OperationFormPreventiveDiag), + ('towns-operation_modification', SelectedTownFormset), + ('townsgeneral-operation_modification', TownFormset), + ('parcels-operation_modification', SelectedParcelFormSet), + ('parcelsgeneral-operation_modification', SelectedParcelGeneralFormSet), + ('remains-operation_modification', RemainFormset), + ('periods-operation_modification', PeriodFormset), + ('final-operation_modification', FinalForm)], + condition_list={ +'preventive-operation_modification':is_preventive( + 'general-operation_modification', models.OperationType, + 'operation_type', 'prev_excavation'), +'preventivediag-operation_modification':is_preventive( + 'general-operation_modification', models.OperationType, + 'operation_type', 'arch_diagnostic'), +'townsgeneral-operation_modification':has_associated_file( + 'general-operation_modification', negate=True), +'towns-operation_modification':has_associated_file( + 'general-operation_modification'), +'parcelsgeneral-operation_modification':has_associated_file( + 'general-operation_modification', negate=True), +'parcels-operation_modification':has_associated_file( + 'general-operation_modification'), + }, + url_name='operation_modification',) + +class OperationClosingWizard(ClosingWizard): + model = models.Operation + fields = ['year', 'operation_code', 'operation_type', 'associated_file', +'in_charge', 'start_date', 'excavation_end_date', 'comment', 'towns', 'remains'] + +class FinalOperationClosingForm(FinalForm): + confirm_msg = " " + confirm_end_msg = _(u"Would you like to close this operation?") + +operation_closing_wizard = OperationClosingWizard([ + ('selec-operation_closing', OperationFormSelection), + ('date-operation_closing', ClosingDateFormSelection), + ('final-operation_closing', FinalOperationClosingForm)], + url_name='operation_closing',) + +class OperationDeletionWizard(DeletionWizard): + model = models.Operation + fields = OperationClosingWizard.fields + +class OperationDeletionForm(FinalForm): + confirm_msg = " " + confirm_end_msg = _(u"Would you like to delete this operation?") + +operation_deletion_wizard = OperationDeletionWizard([ + ('selec-operation_deletion', OperationFormSelection), + ('final-operation_deletion', OperationDeletionForm)], + url_name='operation_deletion',) + +#################################### +# Source management for operations # +#################################### + +class OperationSourceWizard(SourceWizard): + model = models.OperationSource + def get_form_initial(self, request, storage, step): + initial = super(OperationSourceWizard, self).get_form_initial(request, + storage, step) + # put default index and operation_id field in the main source form + general_form_key = 'selec-' + self.url_name + if step.startswith('source-') \ + and self.session_has_key(request, storage, general_form_key): + gen_storage = request.session[storage.prefix]['step_data']\ + [general_form_key] + if general_form_key+"-operation" in gen_storage: + operation_id = int(gen_storage[general_form_key+"-operation"]) + elif general_form_key+"-pk" in gen_storage: + pk = int(gen_storage[general_form_key+"-pk"]) + try: + source = models.OperationSource.objects.get(pk=pk) + operation_id = source.operation.pk + except ObjectDoesNotExist: + pass + if operation_id: + initial['hidden_operation_id'] = operation_id + if 'index' not in initial: + max_val = models.OperationSource.objects.filter( + operation__pk=operation_id).aggregate( + Max('index'))["index__max"] + initial['index'] = max_val and (max_val + 1) or 1 + return initial + +class OperationSourceForm(SourceForm): + pk = forms.IntegerField(required=False, widget=forms.HiddenInput) + index = forms.IntegerField(label=_(u"Index")) + hidden_operation_id = forms.IntegerField(label="", widget=forms.HiddenInput) + + def __init__(self, *args, **kwargs): + super(OperationSourceForm, self).__init__(*args, **kwargs) + keyOrder = self.fields.keyOrder + keyOrder.pop(keyOrder.index('index')) + keyOrder.insert(keyOrder.index('source_type') + 1, 'index') + + def clean(self): + # manage unique operation ID + cleaned_data = self.cleaned_data + operation_id = cleaned_data.get("hidden_operation_id") + index = cleaned_data.get("index") + srcs = models.OperationSource.objects.filter(index=index, + operation__pk=operation_id) + if 'pk' in cleaned_data and cleaned_data['pk']: + srcs = srcs.exclude(pk=cleaned_data['pk']) + if srcs.count(): + max_val = models.OperationSource.objects.filter( + operation__pk=operation_id + ).aggregate(Max('index'))["index__max"] + operation = models.Operation.objects.get(pk=operation_id) + raise forms.ValidationError(_(u"Index already exist for " +"operation: %(operation)s - use a value bigger than %(last_val)d") % { + "operation":unicode(operation), 'last_val':max_val}) + return cleaned_data + +SourceOperationFormSelection = get_form_selection( + 'SourceOperationFormSelection', _(u"Operation search"), 'operation', + models.Operation, OperationSelect, 'get-operation', + _(u"You should select an operation.")) + +operation_source_creation_wizard = OperationSourceWizard([ + ('selec-operation_source_creation', SourceOperationFormSelection), + ('source-operation_source_creation',OperationSourceForm), + ('authors-operation_source_creation', AuthorFormset), + ('final-operation_source_creation', FinalForm)], + url_name='operation_source_creation',) + +class OperationSourceSelect(SourceSelect): + operation__towns = get_town_field(label=_(u"Operation's town")) + operation__operation_type = forms.ChoiceField(label=_(u"Operation type"), + choices=[]) + operation__year = forms.IntegerField(label=_(u"Operation's year")) + + def __init__(self, *args, **kwargs): + super(OperationSourceSelect, self).__init__(*args, **kwargs) + self.fields['operation__operation_type'].choices = \ + models.OperationType.get_types() + self.fields['operation__operation_type'].help_text = \ + models.OperationType.get_help() + + +OperationSourceFormSelection = get_form_selection( + 'OperationSourceFormSelection', _(u"Documentation search"), 'pk', + models.OperationSource, OperationSourceSelect, 'get-operationsource', + _(u"You should select a document.")) + +operation_source_modification_wizard = OperationSourceWizard([ + ('selec-operation_source_modification', OperationSourceFormSelection), + ('source-operation_source_modification', OperationSourceForm), + ('authors-operation_source_modification', AuthorFormset), + ('final-operation_source_modification', FinalForm)], + url_name='operation_source_modification',) + +class OperationSourceDeletionWizard(DeletionWizard): + model = models.OperationSource + fields = ['operation', 'title', 'source_type', 'authors',] + +operation_source_deletion_wizard = OperationSourceDeletionWizard([ + ('selec-operation_source_deletion', OperationSourceFormSelection), + ('final-operation_source_deletion', SourceDeletionForm)], + url_name='operation_source_deletion',) + +################################################ +# Administrative act management for operations # +################################################ + +class OperationAdministrativeActWizard(OperationWizard): + edit = False + + def get_extra_model(self, dct, request, storage, form_list): + dct['history_modifier'] = request.user + return dct + + def get_associated_item(self, request, storage, dct): + return self.get_current_object(request, storage) + + def save_model(self, dct, m2m, whole_associated_models, request, storage, + form_list, return_object): + associated_item = self.get_associated_item(request, storage, dct) + if not associated_item: + return self.render(request, storage, form_list[-1]) + if isinstance(associated_item, models.File): + dct['associated_file'] = associated_item + elif isinstance(associated_item, models.Operation): + dct['operation'] = associated_item + dct['history_modifier'] = request.user + if 'pk' in dct: + dct.pop('pk') + if self.edit: + admact = self.get_current_object(request, storage) + for k in dct: + if hasattr(admact, k): + setattr(admact, k, dct[k]) + else: + admact = models.AdministrativeAct(**dct) + admact.save() + res = render_to_response('wizard_done.html', {}, + context_instance=RequestContext(request)) + return res + +class OperationEditAdministrativeActWizard(OperationAdministrativeActWizard): + model = models.AdministrativeAct + edit = True + def get_associated_item(self, request, storage, dct): + return self.get_current_object(request, storage).operation + +class AdministrativeActOpeSelect(forms.Form): + operation__towns = get_town_field() + act_type = forms.ChoiceField(label=_("Act type"), choices=[]) + + def __init__(self, *args, **kwargs): + super(AdministrativeActOpeSelect, self).__init__(*args, **kwargs) + self.fields['act_type'].choices = models.ActType.get_types( + dct={'intented_to':'O'}) + self.fields['act_type'].help_text = models.ActType.get_help( + dct={'intented_to':'O'}) + +class AdministrativeActOpeFormSelection(forms.Form): + form_label = _("Administrative act search") + associated_models = {'pk':models.AdministrativeAct} + currents = {'pk':models.AdministrativeAct} + pk = forms.IntegerField(label="", required=False, + widget=widgets.JQueryJqGrid(reverse_lazy('get-administrativeactop'), + AdministrativeActOpeSelect(), models.AdministrativeAct, + table_cols='TABLE_COLS_OPE'), + validators=[models.valid_id(models.AdministrativeAct)]) + + def clean(self): + cleaned_data = self.cleaned_data + if 'pk' not in cleaned_data or not cleaned_data['pk']: + raise forms.ValidationError(_(u"You should select an administrative" + " act.")) + return cleaned_data + +class AdministrativeActOpeForm(forms.Form): + form_label = _("General") + associated_models = {'act_type':models.ActType, + 'signatory':models.Person} + act_type = forms.ChoiceField(label=_("Act type"), choices=[]) + signatory = forms.IntegerField(label=_("Signatory"), + widget=widgets.JQueryAutoComplete(reverse_lazy('autocomplete-person'), + associated_model=models.Person, new=True), + validators=[models.valid_id(models.Person)]) + act_object = forms.CharField(label=_(u"Object"), max_length=200, + widget=forms.Textarea) + signature_date = forms.DateField(label=_(u"Signature date"), + widget=widgets.JQueryDate) + if settings.COUNTRY == 'fr': + ref_sra = forms.CharField(label=u"Référence SRA", max_length=15) + + def __init__(self, *args, **kwargs): + super(AdministrativeActOpeForm, self).__init__(*args, **kwargs) + self.fields['act_type'].choices = models.ActType.get_types( + dct={'intented_to':'O'}) + self.fields['act_type'].help_text = models.ActType.get_help( + dct={'intented_to':'O'}) + +class AdministrativeActDeletionWizard(ClosingWizard): + model = models.AdministrativeAct + fields = ['act_type', 'in_charge', 'operator', 'scientific', 'signatory', + 'operation', 'associated_file', 'signature_date', 'act_object',] + if settings.COUNTRY == 'fr': + fields += ['ref_sra'] + + def done(self, request, storage, form_list, **kwargs): + obj = self.get_current_object(request, storage) + obj.delete() + return render_to_response('wizard_done.html', {}, + context_instance=RequestContext(request)) + +class FinalAdministrativeActDeleteForm(FinalForm): + confirm_msg = " " + confirm_end_msg = _(u"Would you like to delete this administrative act?") + +operation_administrativeactop_wizard = OperationAdministrativeActWizard([ + ('selec-operation_administrativeactop', OperationFormSelection), + ('administrativeact-operation_administrativeactop', AdministrativeActOpeForm), + ('final-operation_administrativeactop', FinalForm)], + url_name='operation_administrativeactop',) + +operation_administrativeactop_modification_wizard = \ + OperationEditAdministrativeActWizard([ + ('selec-operation_administrativeactop_modification', + AdministrativeActOpeFormSelection), + ('administrativeact-operation_administrativeactop_modification', + AdministrativeActOpeForm), + ('final-operation_administrativeactop_modification', FinalForm)], + url_name='operation_administrativeactop_modification',) + +operation_administrativeactop_deletion_wizard = AdministrativeActDeletionWizard([ + ('selec-operation_administrativeactop_deletion', + AdministrativeActOpeFormSelection), + ('final-operation_administrativeactop_deletion', + FinalAdministrativeActDeleteForm)], + url_name='operation_administrativeactop_deletion',) diff --git a/ishtar_common/locale/fr/LC_MESSAGES/django.po b/ishtar_common/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 000000000..417406b58 --- /dev/null +++ b/ishtar_common/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,2741 @@ +# Ishtar po translation. +# Copyright (C) 2010-2011 +# This file is distributed under the same license as the Ishtar package. +# Étienne Loks <etienne.loks at peacefrogs net>, 2010-2011. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: alpha\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2011-10-11 20:42+0200\n" +"PO-Revision-Date: 2010-12-09\n" +"Last-Translator: Étienne Loks <etienne.loks at peacefrogs net>\n" +"Language-Team: \n" +"Language: \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" + +# overload of translation of registration module +#: __init__.py:3 +msgid "username" +msgstr "identifiant" + +# overload of translation of registration module +#: __init__.py:4 +msgid "email address" +msgstr "courriel" + +#: __init__.py:5 __init__.py:7 +msgid "warehouse" +msgstr "dépôt" + +#: __init__.py:6 +msgid "New warehouse" +msgstr "Nouveau dépôt" + +#: __init__.py:8 +msgid "New organization" +msgstr "Nouvelle organisation" + +#: __init__.py:9 +msgid "New person" +msgstr "Nouvelle personne" + +#: __init__.py:10 +msgid "New author" +msgstr "Nouvel auteur" + +#: ishtar_base/context_processors.py:42 ishtar_base/menus.py:114 +#: ishtar_base/models.py:1257 +msgid "Archaeological file" +msgstr "Dossier archéologique" + +#: ishtar_base/context_processors.py:43 ishtar_base/menus.py:148 +#: ishtar_base/models.py:1412 ishtar_base/models.py:1530 +#: ishtar_base/models.py:1541 ishtar_base/models.py:1551 +#: ishtar_base/models.py:1658 ishtar_base/models.py:1990 +#: ishtar_base/models.py:2013 +msgid "Operation" +msgstr "Opération" + +#: ishtar_base/context_processors.py:44 ishtar_base/menus.py:190 +#: ishtar_base/models.py:1758 templates/sheet_contextrecord.html:104 +#: templates/sheet_operation.html:150 +msgid "Context record" +msgstr "Unité d'Enregistrement" + +#: ishtar_base/context_processors.py:45 +msgid "Archaeological item" +msgstr "Mobilier" + +#: ishtar_base/forms.py:53 +msgid "Enter a valid name consisting of letters, spaces and hyphens." +msgstr "Entrez un nom correct composé de lettres, espaces et tirets." + +#: ishtar_base/forms.py:66 ishtar_base/forms_common.py:351 +msgid "Confirm" +msgstr "Confirmation" + +#: ishtar_base/forms.py:74 +msgid "There are identical items." +msgstr "Il y a des éléments identiques." + +#: ishtar_base/forms.py:250 +msgid "Yes" +msgstr "Oui" + +#: ishtar_base/forms.py:252 +msgid "No" +msgstr "Non" + +#: ishtar_base/forms.py:733 ishtar_base/forms.py:734 +#: ishtar_base/models.py:1230 ishtar_base/models.py:1368 +msgid "Closing date" +msgstr "Date de clotûre" + +#: ishtar_base/forms.py:788 +msgid "You should select an item." +msgstr "Vous devez sélectionner un élément." + +#: ishtar_base/forms.py:789 +msgid "Add a new item" +msgstr "Ajouter un nouvel élément" + +#: ishtar_base/forms_common.py:44 ishtar_base/forms_common.py:95 +#: ishtar_base/forms_common.py:99 ishtar_base/forms_common.py:132 +#: ishtar_base/forms_common.py:136 ishtar_base/forms_common.py:384 +#: ishtar_base/forms_operations.py:323 ishtar_base/models.py:1060 +#: ishtar_base/models.py:1554 ishtar_base/models.py:2096 +#: templates/dashboard_operation.html:302 +#: templates/dashboard_operation.html:315 +#: templates/dashboard_operation.html:485 +#: templates/dashboard_operation.html:498 +msgid "Town" +msgstr "Commune" + +#: ishtar_base/forms_common.py:45 +msgid "" +"<p>Type name, department code and/or postal code of the town you would like " +"to select. The search is insensitive to case.</p>\n" +"<p>Only the first twenty results are displayed but specifying the department " +"code is generally sufficient to get the appropriate result.</p>\n" +"<p class='example'>For instance type \"saint denis 93\" for getting the " +"french town Saint-Denis in the Seine-Saint-Denis department.</p>" +msgstr "" +"<p>Tapez le nom, le numéro de département et - ou le code postal de la " +"commune que vous voulez sélectionner. La recherche n'est pas sensible à la " +"casse.</p>\n" +"<p>Seuls les vingt premiers résultats sont affichés mais en plus du nom " +"préciser le numéro de département est généralement suffisant pour obtenir le " +"résultat souhaité.</p>\n" +"<p class='example'>Par exemple tapez « saint denis 93 » pour obtenir la " +"commune Saint-Denis dans le département français de Seine-Saint-Denis.</p>" + +#: ishtar_base/forms_common.py:58 ishtar_base/forms_common.py:162 +#: ishtar_base/forms_common.py:491 ishtar_base/forms_items.py:194 +#: ishtar_base/menus.py:101 ishtar_base/models.py:1115 +#: ishtar_base/models.py:1140 ishtar_base/models.py:1152 +#: ishtar_base/models.py:2120 ishtar_base/models.py:2153 +msgid "Person" +msgstr "Individu" + +#: ishtar_base/forms_common.py:70 ishtar_base/forms_items.py:236 +#: ishtar_base/models.py:1976 ishtar_base/models.py:2051 +msgid "Warehouse" +msgstr "Dépôt" + +#: ishtar_base/forms_common.py:78 ishtar_base/forms_common.py:122 +#: ishtar_base/forms_common.py:174 ishtar_base/forms_operations.py:164 +#: ishtar_base/models.py:1077 ishtar_base/models.py:1108 +#: ishtar_base/models.py:1968 ishtar_base/models.py:2082 +msgid "Name" +msgstr "Nom" + +#: ishtar_base/forms_common.py:80 ishtar_base/models.py:1964 +#: ishtar_base/models.py:1970 +msgid "Warehouse type" +msgstr "Type de dépôt" + +#: ishtar_base/forms_common.py:82 ishtar_base/forms_files.py:132 +#: ishtar_base/forms_files.py:164 ishtar_base/models.py:1221 +#: ishtar_base/models.py:1972 +msgid "Person in charge" +msgstr "Responsable" + +#: ishtar_base/forms_common.py:87 ishtar_base/forms_files.py:186 +#: ishtar_base/forms_items.py:241 ishtar_base/forms_operations.py:262 +#: ishtar_base/models.py:144 ishtar_base/models.py:1253 +#: ishtar_base/models.py:1408 ishtar_base/models.py:1973 +#: ishtar_base/models.py:2055 +msgid "Comment" +msgstr "Commentaire" + +#: ishtar_base/forms_common.py:89 ishtar_base/forms_common.py:126 +#: ishtar_base/forms_files.py:198 ishtar_base/models.py:1055 +msgid "Address" +msgstr "Adresse" + +#: ishtar_base/forms_common.py:91 ishtar_base/forms_common.py:128 +#: ishtar_base/models.py:1056 +msgid "Address complement" +msgstr "Complément d'adresse" + +#: ishtar_base/forms_common.py:93 ishtar_base/forms_common.py:130 +#: ishtar_base/models.py:1058 +msgid "Postal code" +msgstr "Code postal" + +#: ishtar_base/forms_common.py:96 ishtar_base/forms_common.py:133 +#: ishtar_base/models.py:1061 +msgid "Country" +msgstr "Pays" + +#: ishtar_base/forms_common.py:98 ishtar_base/forms_common.py:135 +#: ishtar_base/models.py:1063 +msgid "Phone" +msgstr "Téléphone" + +#: ishtar_base/forms_common.py:124 ishtar_base/models.py:1073 +msgid "Organization type" +msgstr "Type d'organisation" + +#: ishtar_base/forms_common.py:159 +msgid "Person search" +msgstr "Recherche d'individus" + +#: ishtar_base/forms_common.py:168 +msgid "Identity" +msgstr "Identité" + +#: ishtar_base/forms_common.py:171 ishtar_base/forms_common.py:448 +#: ishtar_base/models.py:1106 ishtar_base/models.py:1168 +#: templates/sheet_contextrecord.html:82 templates/sheet_ope.html:104 +#: templates/sheet_ope_modif.html:104 templates/sheet_operation.html:104 +msgid "Title" +msgstr "Titre" + +#: ishtar_base/forms_common.py:172 ishtar_base/models.py:1107 +msgid "Surname" +msgstr "Prénom" + +#: ishtar_base/forms_common.py:176 ishtar_base/forms_common.py:309 +#: ishtar_base/models.py:1109 +msgid "Email" +msgstr "Courriel" + +#: ishtar_base/forms_common.py:178 ishtar_base/models.py:1097 +msgid "Person type" +msgstr "Type d'individu" + +#: ishtar_base/forms_common.py:180 +msgid "Current organization" +msgstr "Organisation actuelle" + +#: ishtar_base/forms_common.py:227 ishtar_base/forms_common.py:311 +msgid "New password" +msgstr "Nouveau mot de passe" + +#: ishtar_base/forms_common.py:281 +#, python-format +msgid "[%(app_name)s] Account creation/modification" +msgstr "[%(app_name)s] Création - modification du compte" + +#: ishtar_base/forms_common.py:304 ishtar_base/forms_common.py:308 +msgid "Account" +msgstr "Compte" + +#: ishtar_base/forms_common.py:315 +msgid "New password (confirmation)" +msgstr "Nouveau mot de passe (confirmation)" + +#: ishtar_base/forms_common.py:333 +msgid "Your password and confirmation password do not match." +msgstr "La vérification du mot de passe a échoué." + +#: ishtar_base/forms_common.py:338 +msgid "You must provide a correct password." +msgstr "Vous devez fournir un mot de passe correct." + +#: ishtar_base/forms_common.py:346 +msgid "This username already exists." +msgstr "Ce nom d'utilisateur existe déjà." + +#: ishtar_base/forms_common.py:352 +msgid "Send the new password by email?" +msgstr "Envoyer le nouveau mot de passe par courriel ?" + +#: ishtar_base/forms_common.py:366 ishtar_base/forms_common.py:378 +#: ishtar_base/forms_operations.py:321 ishtar_base/forms_operations.py:342 +#: ishtar_base/models.py:1231 ishtar_base/models.py:1379 +#: ishtar_base/models.py:2097 +msgid "Towns" +msgstr "Communes" + +#: ishtar_base/forms_common.py:375 +msgid "There are identical towns." +msgstr "Il y a des communes identiques." + +#: ishtar_base/forms_common.py:381 ishtar_base/forms_common.py:430 +#: ishtar_base/forms_operations.py:345 ishtar_base/forms_operations.py:366 +#: ishtar_base/forms_operations.py:370 ishtar_base/models.py:1560 +msgid "Parcels" +msgstr "Parcelles" + +#: ishtar_base/forms_common.py:386 ishtar_base/models.py:1555 +#: templates/sheet_ope.html:62 templates/sheet_ope_modif.html:62 +#: templates/sheet_operation.html:63 +msgid "Section" +msgstr "Section" + +#: ishtar_base/forms_common.py:388 ishtar_base/models.py:1556 +msgid "Parcel number" +msgstr "Numéro de parcelle" + +#: ishtar_base/forms_common.py:390 ishtar_base/forms_context_records.py:116 +#: ishtar_base/forms_files.py:137 ishtar_base/forms_files.py:169 +#: ishtar_base/forms_files.py:190 ishtar_base/forms_items.py:142 +#: ishtar_base/forms_operations.py:170 ishtar_base/forms_operations.py:246 +#: ishtar_base/models.py:980 ishtar_base/models.py:1214 +#: ishtar_base/models.py:1371 ishtar_base/models.py:1552 +#: templates/sheet_file.html:68 templates/sheet_file.html.py:88 +#: templates/sheet_file.html:116 templates/sheet_ope.html:61 +#: templates/sheet_ope.html.py:83 templates/sheet_ope_modif.html:61 +#: templates/sheet_ope_modif.html.py:83 templates/sheet_operation.html:62 +#: templates/sheet_operation.html.py:83 +msgid "Year" +msgstr "Année" + +#: ishtar_base/forms_common.py:417 +msgid "Town section and parcel number fields are required." +msgstr "La commune, la section et le numéro de parcelle sont obligatoire." + +#: ishtar_base/forms_common.py:426 +msgid "There are identical parcels." +msgstr "Il y a des parcelles identiques." + +#: ishtar_base/forms_common.py:446 +msgid "Documentation informations" +msgstr "Information sur le document" + +#: ishtar_base/forms_common.py:450 ishtar_base/forms_common.py:469 +#: ishtar_base/models.py:1164 +msgid "Source type" +msgstr "Type de source" + +#: ishtar_base/forms_common.py:452 ishtar_base/models.py:1172 +msgid "Numerical ressource (web address)" +msgstr "Ressource numérique (adresse web)" + +#: ishtar_base/forms_common.py:453 ishtar_base/models.py:1174 +msgid "Receipt date" +msgstr "Date de réception" + +#: ishtar_base/forms_common.py:455 ishtar_base/forms_files.py:178 +#: ishtar_base/models.py:1176 ishtar_base/models.py:1233 +msgid "Creation date" +msgstr "Date de création" + +#: ishtar_base/forms_common.py:466 ishtar_base/forms_common.py:485 +#: ishtar_base/forms_common.py:515 ishtar_base/models.py:1156 +msgid "Author" +msgstr "Auteur" + +#: ishtar_base/forms_common.py:478 +msgid "Would you like to delete this documentation?" +msgstr "Voulez vous supprimer ce document ?" + +#: ishtar_base/forms_common.py:492 ishtar_base/models.py:1148 +#: ishtar_base/models.py:1153 +msgid "Author type" +msgstr "Type d'auteur" + +#: ishtar_base/forms_common.py:509 +msgid "Author selection" +msgstr "Sélection d'auteur" + +#: ishtar_base/forms_common.py:521 +msgid "There are identical authors." +msgstr "Il y a des auteurs identiques." + +#: ishtar_base/forms_common.py:525 ishtar_base/models.py:1157 +#: ishtar_base/models.py:1170 templates/sheet_contextrecord.html:84 +#: templates/sheet_ope.html:106 templates/sheet_ope_modif.html:106 +#: templates/sheet_operation.html:106 +msgid "Authors" +msgstr "Auteurs" + +#: ishtar_base/forms_context_records.py:77 ishtar_base/forms_items.py:81 +msgid "Current operation: " +msgstr "Opération : " + +#: ishtar_base/forms_context_records.py:117 +#: ishtar_base/forms_context_records.py:213 ishtar_base/forms_items.py:117 +#: ishtar_base/forms_items.py:145 ishtar_base/forms_operations.py:393 +#: ishtar_base/models.py:1600 +msgid "Period" +msgstr "Période" + +#: ishtar_base/forms_context_records.py:118 +msgid "Unit type" +msgstr "Type d'unité" + +#: ishtar_base/forms_context_records.py:129 +#: ishtar_base/forms_context_records.py:312 +msgid "Context record search" +msgstr "Recherche d'Unité d'Enregistrement" + +#: ishtar_base/forms_context_records.py:141 +msgid "You should at least select one context record." +msgstr "Vous devez sélectionner au moins une Unité d'Enregistrement." + +#: ishtar_base/forms_context_records.py:147 ishtar_base/forms_files.py:160 +#: ishtar_base/forms_operations.py:219 ishtar_base/forms_operations.py:695 +#: templates/sheet_file.html:17 templates/sheet_ope.html:5 +#: templates/sheet_ope_modif.html:5 templates/sheet_operation.html:5 +msgid "General" +msgstr "Général" + +#: ishtar_base/forms_context_records.py:151 +#: ishtar_base/forms_operations.py:347 ishtar_base/models.py:1559 +#: ishtar_base/models.py:1656 ishtar_base/models.py:1951 +#: templates/sheet_contextrecord.html:109 templates/sheet_ope.html:63 +#: templates/sheet_ope.html.py:129 templates/sheet_ope_modif.html:63 +#: templates/sheet_ope_modif.html.py:129 templates/sheet_ope_modif.html:157 +#: templates/sheet_operation.html:64 templates/sheet_operation.html.py:128 +#: templates/sheet_operation.html:155 +msgid "Parcel" +msgstr "Parcelle" + +#: ishtar_base/forms_context_records.py:152 ishtar_base/forms_items.py:99 +#: ishtar_base/forms_items.py:285 ishtar_base/models.py:1660 +#: ishtar_base/models.py:1770 ishtar_base/models.py:1843 +#: templates/sheet_ope.html:125 templates/sheet_ope_modif.html:125 +#: templates/sheet_operation.html:124 +msgid "ID" +msgstr "Identifiant" + +#: ishtar_base/forms_context_records.py:154 ishtar_base/forms_items.py:101 +#: ishtar_base/forms_items.py:148 ishtar_base/forms_items.py:203 +#: ishtar_base/models.py:1661 ishtar_base/models.py:1771 +#: ishtar_base/models.py:1844 ishtar_base/models.py:2115 +#: templates/sheet_contextrecord.html:23 +#: templates/sheet_contextrecord.html:106 templates/sheet_ope.html:128 +#: templates/sheet_ope_modif.html:128 templates/sheet_ope_modif.html.py:154 +#: templates/sheet_operation.html:127 templates/sheet_operation.html.py:152 +msgid "Description" +msgstr "Description" + +#: ishtar_base/forms_context_records.py:156 ishtar_base/models.py:1662 +msgid "Length (cm)" +msgstr "Longueur (cm)" + +#: ishtar_base/forms_context_records.py:157 ishtar_base/models.py:1663 +msgid "Width (cm)" +msgstr "Largeur (cm)" + +#: ishtar_base/forms_context_records.py:158 ishtar_base/models.py:1664 +msgid "Thickness (cm)" +msgstr "Épaisseur (cm)" + +#: ishtar_base/forms_context_records.py:159 ishtar_base/models.py:1665 +msgid "Depth (cm)" +msgstr "Profondeur (cm)" + +#: ishtar_base/forms_context_records.py:160 ishtar_base/models.py:1670 +msgid "Unit" +msgstr "Unité" + +#: ishtar_base/forms_context_records.py:162 ishtar_base/forms_items.py:198 +#: ishtar_base/models.py:1666 ishtar_base/models.py:2118 +msgid "Location" +msgstr "Lieu" + +#: ishtar_base/forms_context_records.py:203 +msgid "This ID already exist for this operation." +msgstr "Cet identifiant existe déjà pour cette opération." + +#: ishtar_base/forms_context_records.py:208 +#: ishtar_base/forms_context_records.py:230 ishtar_base/forms_items.py:112 +#: ishtar_base/models.py:1609 ishtar_base/models.py:1854 +msgid "Dating" +msgstr "Datation" + +#: ishtar_base/forms_context_records.py:215 ishtar_base/forms_items.py:119 +#: ishtar_base/forms_items.py:205 ishtar_base/forms_operations.py:238 +#: ishtar_base/models.py:1365 ishtar_base/models.py:1577 +#: ishtar_base/models.py:1601 ishtar_base/models.py:1952 +#: ishtar_base/models.py:2122 ishtar_base/models.py:2154 +#: templates/sheet_file.html:93 +msgid "Start date" +msgstr "Date de début" + +#: ishtar_base/forms_context_records.py:216 ishtar_base/forms_items.py:121 +#: ishtar_base/forms_items.py:207 ishtar_base/models.py:1578 +#: ishtar_base/models.py:1602 ishtar_base/models.py:1953 +#: ishtar_base/models.py:2123 ishtar_base/models.py:2155 +msgid "End date" +msgstr "Date de fin" + +#: ishtar_base/forms_context_records.py:217 ishtar_base/forms_items.py:122 +#: ishtar_base/models.py:1605 +msgid "Quality" +msgstr "Qualité" + +#: ishtar_base/forms_context_records.py:219 ishtar_base/forms_items.py:124 +#: ishtar_base/models.py:1591 ishtar_base/models.py:1603 +msgid "Dating type" +msgstr "Type de datation" + +#: ishtar_base/forms_context_records.py:233 +#: ishtar_base/forms_context_records.py:240 ishtar_base/models.py:1675 +#: templates/sheet_contextrecord.html:32 +msgid "Interpretation" +msgstr "Interpretation" + +#: ishtar_base/forms_context_records.py:236 +msgid "Has furniture?" +msgstr "A du matériel ?" + +#: ishtar_base/forms_context_records.py:238 ishtar_base/models.py:1674 +msgid "Filling" +msgstr "Remplissage" + +#: ishtar_base/forms_context_records.py:242 ishtar_base/models.py:1690 +msgid "Activity" +msgstr "Activité" + +#: ishtar_base/forms_context_records.py:244 ishtar_base/models.py:1688 +msgid "Identification" +msgstr "Identification" + +#: ishtar_base/forms_context_records.py:246 ishtar_base/models.py:1677 +msgid "TAQ" +msgstr "TAQ" + +#: ishtar_base/forms_context_records.py:247 ishtar_base/models.py:1680 +msgid "Estimated TAQ" +msgstr "TAQ estimé" + +#: ishtar_base/forms_context_records.py:249 ishtar_base/models.py:1682 +msgid "TPQ" +msgstr "TPQ" + +#: ishtar_base/forms_context_records.py:250 ishtar_base/models.py:1685 +msgid "Estimated TPQ" +msgstr "TPQ estimé" + +#: ishtar_base/forms_context_records.py:267 +#: ishtar_base/forms_operations.py:179 ishtar_base/forms_operations.py:576 +msgid "Operation search" +msgstr "Recherche d'opérations" + +#: ishtar_base/forms_context_records.py:269 +#: ishtar_base/forms_operations.py:191 ishtar_base/forms_operations.py:578 +msgid "You should select an operation." +msgstr "Vous devez sélectionner une opération." + +#: ishtar_base/forms_context_records.py:297 +msgid "Would you like to delete this context record?" +msgstr "Voulez vous supprimer cette Unité d'Enregistrement ?" + +#: ishtar_base/forms_context_records.py:314 +msgid "You should select a context record." +msgstr "Vous devez sélectionner une Unité d'Enregistrement." + +#: ishtar_base/forms_context_records.py:325 +msgid "Town of the operation" +msgstr "Commune de l'opération" + +#: ishtar_base/forms_context_records.py:327 ishtar_base/forms_items.py:428 +msgid "Year of the operation" +msgstr "Année de l'opération" + +#: ishtar_base/forms_context_records.py:329 +msgid "Period of the context record" +msgstr "Période de l'Unité d'Enregistrement" + +#: ishtar_base/forms_context_records.py:331 +msgid "Unit type of the context record" +msgstr "Type d'unité de l'Unité d'Enregistrement" + +#: ishtar_base/forms_context_records.py:344 ishtar_base/forms_items.py:450 +#: ishtar_base/forms_operations.py:602 +msgid "Documentation search" +msgstr "Recherche de document" + +#: ishtar_base/forms_context_records.py:346 ishtar_base/forms_items.py:452 +#: ishtar_base/forms_operations.py:604 +msgid "You should select a document." +msgstr "Vous devez sélectionner un document." + +#: ishtar_base/forms_files.py:134 ishtar_base/forms_files.py:180 +#: ishtar_base/models.py:1219 +msgid "File type" +msgstr "Type de dossier" + +#: ishtar_base/forms_files.py:136 ishtar_base/forms_files.py:239 +msgid "Saisine type" +msgstr "Type de saisine" + +#: ishtar_base/forms_files.py:145 +msgid "Archaeological file search" +msgstr "Recherche de dossiers archéologiques" + +#: ishtar_base/forms_files.py:156 +msgid "You should select a file." +msgstr "Vous devez sélectionner un dossier archéologique." + +#: ishtar_base/forms_files.py:173 ishtar_base/forms_files.py:192 +#: ishtar_base/models.py:1216 +msgid "Numeric reference" +msgstr "Référence numérique" + +#: ishtar_base/forms_files.py:175 ishtar_base/forms_files.py:194 +#: ishtar_base/models.py:1217 +msgid "Internal reference" +msgstr "Référence interne" + +#: ishtar_base/forms_files.py:182 ishtar_base/models.py:1237 +msgid "Related file" +msgstr "Dossier en relation avec" + +#: ishtar_base/forms_files.py:202 ishtar_base/forms_operations.py:243 +#: ishtar_base/models.py:1244 templates/dashboard_operation.html:315 +msgid "Total surface (m²)" +msgstr "Surface totale (m²)" + +#: ishtar_base/forms_files.py:205 ishtar_base/models.py:1248 +msgid "Main address" +msgstr "Adresse principale" + +#: ishtar_base/forms_files.py:206 ishtar_base/models.py:1249 +msgid "Main address - complement" +msgstr "Adresse principale - complément" + +#: ishtar_base/forms_files.py:208 ishtar_base/models.py:1251 +msgid "Main address - postal code" +msgstr "Adresse principale - code postal" + +#: ishtar_base/forms_files.py:212 +msgid "Preventive informations" +msgstr "Information archéologie préventive" + +#: ishtar_base/forms_files.py:217 ishtar_base/models.py:1223 +msgid "General contractor" +msgstr "Aménageur" + +#: ishtar_base/forms_files.py:224 ishtar_base/models.py:1225 +msgid "Town planning service" +msgstr "Service instructeur" + +#: ishtar_base/forms_files.py:230 ishtar_base/models.py:1201 +#: ishtar_base/models.py:1226 +msgid "Permit type" +msgstr "Type de permis" + +#: ishtar_base/forms_files.py:232 ishtar_base/models.py:1228 +msgid "Permit reference" +msgstr "Référence du permis" + +#: ishtar_base/forms_files.py:235 ishtar_base/models.py:1247 +msgid "Total developed surface (m²)" +msgstr "Surface totale aménagée (m²)" + +#: ishtar_base/forms_files.py:241 ishtar_base/models.py:1235 +msgid "Reception date" +msgstr "Date de réception" + +#: ishtar_base/forms_files.py:293 +msgid "Would you like to close this archaeological file?" +msgstr "Voulez vous clôturer ce dossier archéologique ?" + +#: ishtar_base/forms_files.py:304 templates/sheet_file.html:86 +msgid "Associated operations" +msgstr "Opérations associées" + +#: ishtar_base/forms_files.py:323 +msgid "Would you like to delete this archaelogical file ?" +msgstr "Voulez vous supprimer ce dossier archéologique ?" + +#: ishtar_base/forms_files.py:341 ishtar_base/forms_files.py:358 +#: ishtar_base/forms_operations.py:668 ishtar_base/forms_operations.py:698 +#: ishtar_base/models.py:1995 ishtar_base/models.py:2003 +msgid "Act type" +msgstr "Type d'acte" + +#: ishtar_base/forms_items.py:82 +msgid "Current context record: " +msgstr "Unité d'Enregistrement : " + +#: ishtar_base/forms_items.py:96 ishtar_base/menus.py:209 +#: ishtar_base/models.py:1912 ishtar_base/models.py:1946 +#: ishtar_base/models.py:2150 +msgid "Item" +msgstr "Mobilier" + +#: ishtar_base/forms_items.py:103 ishtar_base/forms_items.py:149 +#: ishtar_base/models.py:1774 +msgid "Is isolated?" +msgstr "Est isolé ?" + +#: ishtar_base/forms_items.py:105 ishtar_base/forms_items.py:147 +#: ishtar_base/forms_items.py:289 ishtar_base/models.py:1766 +#: ishtar_base/models.py:1846 templates/sheet_contextrecord.html:103 +#: templates/sheet_operation.html:149 +msgid "Material type" +msgstr "Type de matériau" + +#: ishtar_base/forms_items.py:107 ishtar_base/forms_items.py:291 +#: ishtar_base/models.py:1847 ishtar_base/models.py:2042 +msgid "Volume (l)" +msgstr "Volume (l)" + +#: ishtar_base/forms_items.py:108 ishtar_base/forms_items.py:292 +#: ishtar_base/models.py:1848 +msgid "Weight (g)" +msgstr "Poids (g)" + +#: ishtar_base/forms_items.py:109 ishtar_base/forms_items.py:293 +#: ishtar_base/models.py:1849 +msgid "Item number" +msgstr "Nombre d'éléments" + +#: ishtar_base/forms_items.py:144 +msgid "Code PATRIARCHE" +msgstr "Code PATRIARCHE" + +#: ishtar_base/forms_items.py:163 +msgid "Item search" +msgstr "Recherche de mobilier" + +#: ishtar_base/forms_items.py:189 +msgid "Base treatment" +msgstr "Traitement de base" + +#: ishtar_base/forms_items.py:193 ishtar_base/models.py:2109 +#: ishtar_base/models.py:2117 +msgid "Treatment type" +msgstr "Type de traitement" + +#: ishtar_base/forms_items.py:218 +msgid "Upstream items" +msgstr "Mobilier amont" + +#: ishtar_base/forms_items.py:220 ishtar_base/models.py:1913 +msgid "Items" +msgstr "Mobiliers" + +#: ishtar_base/forms_items.py:228 +msgid "You should at least select one archaeological item." +msgstr "Vous devez sélectionner du mobilier archéologique." + +#: ishtar_base/forms_items.py:233 ishtar_base/models.py:1855 +#: ishtar_base/models.py:2058 ishtar_base/models.py:2113 +msgid "Container" +msgstr "Contenant" + +#: ishtar_base/forms_items.py:234 ishtar_base/forms_items.py:358 +#: ishtar_base/models.py:2043 ishtar_base/models.py:2054 +#: templates/sheet_file.html:69 templates/sheet_file.html.py:89 +#: templates/sheet_file.html:117 templates/sheet_ope.html:84 +#: templates/sheet_ope_modif.html:84 templates/sheet_operation.html:84 +msgid "Reference" +msgstr "Référence" + +#: ishtar_base/forms_items.py:235 ishtar_base/forms_items.py:357 +#: ishtar_base/models.py:2046 ishtar_base/models.py:2053 +msgid "Container type" +msgstr "Type de contenant" + +#: ishtar_base/forms_items.py:283 +msgid "Resulting item" +msgstr "Mobilier résultant" + +#: ishtar_base/forms_items.py:287 +msgid "Precise description" +msgstr "Description précise" + +#: ishtar_base/forms_items.py:297 +msgid "Resulting items" +msgstr "Mobiliers résultants" + +#: ishtar_base/forms_items.py:300 +msgid "Upstream item" +msgstr "Mobilier amont" + +#: ishtar_base/forms_items.py:368 +msgid "Container search" +msgstr "Recherche de conteneur" + +#: ishtar_base/forms_items.py:370 +msgid "You should select a container." +msgstr "Vous devez sélectionner un conteneur." + +#: ishtar_base/forms_items.py:371 +msgid "Add a new container" +msgstr "Ajouter un nouveau conteneur." + +#: ishtar_base/forms_items.py:374 ishtar_base/menus.py:223 +msgid "Packaging" +msgstr "Conditionnement" + +#: ishtar_base/forms_items.py:379 +msgid "Packager" +msgstr "Personne assurant le conditionnement" + +#: ishtar_base/forms_items.py:383 templates/sheet_file.html:71 +#: templates/sheet_file.html.py:119 templates/sheet_ope.html:86 +#: templates/sheet_ope_modif.html:86 templates/sheet_operation.html:86 +msgid "Date" +msgstr "Date" + +#: ishtar_base/forms_items.py:392 +msgid "Packaged items" +msgstr "Mobilier conditionné" + +#: ishtar_base/forms_items.py:415 +msgid "Archaelogical item search" +msgstr "Recherche de mobilier" + +#: ishtar_base/forms_items.py:417 +msgid "You should select an archaelogical item." +msgstr "Vous devez sélectionner du mobilier." + +#: ishtar_base/forms_items.py:430 +msgid "Period of the archaelogical item" +msgstr "Période du mobilier" + +#: ishtar_base/forms_items.py:433 +msgid "Material type of the archaelogical item" +msgstr "Type de matériau du mobilier" + +#: ishtar_base/forms_items.py:436 +msgid "Description of the archaelogical item" +msgstr "Description du mobilier" + +#: ishtar_base/forms_operations.py:158 +msgid "" +"Warning: No Archaelogical File is provided. If you have forget it return to " +"the first step." +msgstr "" +"Attention : Aucun dossier archéologique n'a été précisé. S'il s'agit d'un " +"oubli, définissez le à la première étape." + +#: ishtar_base/forms_operations.py:166 ishtar_base/forms_operations.py:236 +#: ishtar_base/forms_operations.py:589 ishtar_base/models.py:1345 +#: ishtar_base/models.py:1376 +msgid "Operation type" +msgstr "Type d'opération" + +#: ishtar_base/forms_operations.py:168 ishtar_base/models.py:1378 +msgid "Remains" +msgstr "Vestiges" + +#: ishtar_base/forms_operations.py:171 +msgid "Is open?" +msgstr "Est ouvert ?" + +#: ishtar_base/forms_operations.py:225 ishtar_base/models.py:2005 +msgid "Person in charge of the operation" +msgstr "Responsable d'opération" + +#: ishtar_base/forms_operations.py:232 ishtar_base/models.py:1989 +#: ishtar_base/models.py:2015 +msgid "Archaelogical file" +msgstr "Dossier archéologique" + +#: ishtar_base/forms_operations.py:240 ishtar_base/models.py:1366 +#: templates/sheet_file.html:94 +msgid "Excavation end date" +msgstr "Date de fin de chantier" + +#: ishtar_base/forms_operations.py:250 ishtar_base/models.py:1372 +#: ishtar_base/models.py:1450 +msgid "Operation code" +msgstr "Code de l'opération" + +#: ishtar_base/forms_operations.py:253 ishtar_base/models.py:1406 +msgid "Generic name" +msgstr "Nom générique" + +#: ishtar_base/forms_operations.py:255 ishtar_base/models.py:1404 +msgid "Operator reference" +msgstr "Référence de l'opérateur" + +#: ishtar_base/forms_operations.py:275 +msgid "" +"If you want to set an excavation end date you have to provide a start date." +msgstr "" +"Avant de renseigner la date de fin de chantier, il est nécessaire de " +"renseigner une date de début." + +#: ishtar_base/forms_operations.py:278 +msgid "The excavation end date cannot be before the start date." +msgstr "La date de fin de chantier ne peut être avant la date de début." + +#: ishtar_base/forms_operations.py:290 +#, python-format +msgid "" +"Operation code already exist for year: %(year)d - use a value bigger than " +"%(last_val)d" +msgstr "" +"Ce code d'opération existe déjà pour l'année %(year)d - utilisez une valeur " +"plus grande que %(last_val)d" + +#: ishtar_base/forms_operations.py:296 +msgid "Preventive informations - excavation" +msgstr "Information archéologie préventive - fouille" + +#: ishtar_base/forms_operations.py:297 ishtar_base/models.py:1380 +#: templates/dashboard_operation.html:498 +msgid "Cost (€)" +msgstr "Cout (€)" + +#: ishtar_base/forms_operations.py:298 ishtar_base/models.py:1382 +msgid "Scheduled man-days" +msgstr "Jours-hommes prévus" + +#: ishtar_base/forms_operations.py:300 ishtar_base/models.py:1384 +msgid "Optional man-days" +msgstr "Jours-hommes optionnels" + +#: ishtar_base/forms_operations.py:302 ishtar_base/models.py:1386 +msgid "Effective man-days" +msgstr "Jours-hommes effectifs" + +#: ishtar_base/forms_operations.py:311 +msgid "Preventive informations - diagnostic" +msgstr "Information archéologie préventive - diagnostic" + +#: ishtar_base/forms_operations.py:314 ishtar_base/models.py:1399 +msgid "Prescription on zoning" +msgstr "Prescription sur zonage" + +#: ishtar_base/forms_operations.py:316 ishtar_base/models.py:1401 +msgid "Prescription on large area" +msgstr "Prescription sur une vaste surface" + +#: ishtar_base/forms_operations.py:318 ishtar_base/models.py:1403 +msgid "Prescription on geoarchaeological context" +msgstr "Prescription sur un contexte géoarchéologique" + +#: ishtar_base/forms_operations.py:373 ishtar_base/forms_operations.py:387 +#: ishtar_base/models.py:1360 +msgid "Remain types" +msgstr "Types de vestige" + +#: ishtar_base/forms_operations.py:376 ishtar_base/models.py:1359 +msgid "Remain type" +msgstr "Type de vestige" + +#: ishtar_base/forms_operations.py:383 +msgid "There are identical remain types" +msgstr "Il y a des types de vestige identiques." + +#: ishtar_base/forms_operations.py:390 ishtar_base/forms_operations.py:404 +#: ishtar_base/models.py:1381 templates/sheet_contextrecord.html:105 +#: templates/sheet_ope_modif.html:153 templates/sheet_operation.html:151 +msgid "Periods" +msgstr "Périodes" + +#: ishtar_base/forms_operations.py:400 +msgid "There are identical periods" +msgstr "Il y a des périodes identiques." + +#: ishtar_base/forms_operations.py:491 +msgid "Would you like to close this operation?" +msgstr "Voulez vous clôturer cette opération ?" + +#: ishtar_base/forms_operations.py:505 +msgid "Would you like to delete this operation?" +msgstr "Voulez vous supprimer cette opération ?" + +#: ishtar_base/forms_operations.py:547 ishtar_base/models.py:1543 +msgid "Index" +msgstr "Index" + +#: ishtar_base/forms_operations.py:570 +#, python-format +msgid "" +"Index already exist for operation: %(operation)s - use a value bigger than " +"%(last_val)d" +msgstr "" +"Cet index existe déjà pour l'opération : %(operation)s, utilisez une valeur " +"plus grande que %(last_val)d" + +#: ishtar_base/forms_operations.py:588 +msgid "Operation's town" +msgstr "Commune de l'opération" + +#: ishtar_base/forms_operations.py:591 +msgid "Operation's year" +msgstr "Année de l'opération" + +#: ishtar_base/forms_operations.py:678 +msgid "Administrative act search" +msgstr "Recherche d'actes administratifs" + +#: ishtar_base/forms_operations.py:690 +msgid "You should select an administrative act." +msgstr "Vous devez sélectionner un acte administratif." + +#: ishtar_base/forms_operations.py:699 ishtar_base/models.py:2011 +msgid "Signatory" +msgstr "Signataire" + +#: ishtar_base/forms_operations.py:703 ishtar_base/models.py:2018 +msgid "Object" +msgstr "Objet" + +#: ishtar_base/forms_operations.py:705 ishtar_base/models.py:2016 +msgid "Signature date" +msgstr "Date de signature" + +#: ishtar_base/forms_operations.py:732 +msgid "Would you like to delete this administrative act?" +msgstr "Voulez vous supprimer cet acte administratif ?" + +#: ishtar_base/menus.py:100 +msgid "Administration" +msgstr "Administration" + +#: ishtar_base/menus.py:103 ishtar_base/menus.py:119 ishtar_base/menus.py:154 +#: ishtar_base/menus.py:196 ishtar_base/menus.py:215 +msgid "Creation" +msgstr "Création" + +#: ishtar_base/menus.py:106 ishtar_base/menus.py:122 ishtar_base/menus.py:139 +#: ishtar_base/menus.py:158 ishtar_base/menus.py:179 ishtar_base/menus.py:200 +#: ishtar_base/menus.py:219 +msgid "Modification" +msgstr "Modification" + +#: ishtar_base/menus.py:110 +msgid "Account management" +msgstr "Gestion des comptes" + +#: ishtar_base/menus.py:116 ishtar_base/menus.py:150 ishtar_base/menus.py:192 +#: ishtar_base/menus.py:211 ishtar_base/widgets.py:212 +msgid "Search" +msgstr "Recherche" + +#: ishtar_base/menus.py:125 ishtar_base/menus.py:162 +msgid "Closing" +msgstr "Clotûre" + +#: ishtar_base/menus.py:129 ishtar_base/menus.py:143 ishtar_base/menus.py:166 +#: ishtar_base/menus.py:184 ishtar_base/menus.py:204 ishtar_base/menus.py:269 +msgid "Deletion" +msgstr "Suppression" + +#: ishtar_base/menus.py:132 ishtar_base/menus.py:171 +#: ishtar_base/models.py:2024 ishtar_base/models.py:2152 +msgid "Administrative act" +msgstr "Acte administratif" + +#: ishtar_base/menus.py:135 ishtar_base/menus.py:174 ishtar_base/menus.py:233 +#: ishtar_base/widgets.py:263 templates/window.html:37 +msgid "Add" +msgstr "Ajout" + +#: ishtar_base/menus.py:231 templates/sheet_ope.html:100 +#: templates/sheet_ope_modif.html:100 +msgid "Documentation" +msgstr "Documentation" + +#: ishtar_base/menus.py:236 ishtar_base/menus.py:254 ishtar_base/menus.py:272 +msgid "Related to an operation" +msgstr "Associé à une operation" + +#: ishtar_base/menus.py:241 ishtar_base/menus.py:259 ishtar_base/menus.py:277 +msgid "Related to a context record" +msgstr "Associé à une Unité d'Enregistrement" + +#: ishtar_base/menus.py:246 ishtar_base/menus.py:264 ishtar_base/menus.py:282 +msgid "Related to an archaelogical item" +msgstr "Associé à du mobilier" + +#: ishtar_base/menus.py:251 +msgid "Modify" +msgstr "Modifier" + +#: ishtar_base/menus.py:300 +msgid "Dashboard" +msgstr "Tableau de bord" + +#: ishtar_base/menus.py:302 +msgid "General informations" +msgstr "Informations générales" + +#: ishtar_base/menus.py:305 ishtar_base/models.py:1258 +#: ishtar_base/views.py:695 templates/dashboard_file.html:9 +msgid "Archaeological files" +msgstr "Dossiers archéologiques" + +#: ishtar_base/menus.py:308 ishtar_base/models.py:1413 +#: ishtar_base/views.py:696 templates/dashboard_operation.html:9 +msgid "Operations" +msgstr "Opérations" + +#: ishtar_base/models.py:67 +msgid "Not a valid item." +msgstr "Élément invalide." + +#: ishtar_base/models.py:79 +msgid "An item selected is not a valid item." +msgstr "Un élément sélectionné n'est pas valide." + +#: ishtar_base/models.py:89 +msgid "This item already exist." +msgstr "Cet élément existe déjà." + +#: ishtar_base/models.py:141 ishtar_base/models.py:372 +#: ishtar_base/models.py:1043 +msgid "Label" +msgstr "Libellé" + +#: ishtar_base/models.py:142 +msgid "Textual ID" +msgstr "Identifiant textuel" + +#: ishtar_base/models.py:145 +msgid "Available" +msgstr "Disponible" + +#: ishtar_base/models.py:251 +msgid "Last editor" +msgstr "Dernier éditeur" + +#: ishtar_base/models.py:360 ishtar_base/models.py:371 +msgid "URL name" +msgstr "Nom de l'URL" + +#: ishtar_base/models.py:362 ishtar_base/models.py:370 +msgid "Wizard" +msgstr "Assistant" + +#: ishtar_base/models.py:369 ishtar_base/models.py:1576 +#: ishtar_base/models.py:1620 ishtar_base/models.py:1632 +#: ishtar_base/models.py:1642 ishtar_base/models.py:1842 +msgid "Order" +msgstr "Ordre" + +#: ishtar_base/models.py:374 +msgid "Wizard step" +msgstr "Étape de l'assistant" + +#: ishtar_base/models.py:527 +msgid "Recorded" +msgstr "Enregistré" + +#: ishtar_base/models.py:528 +msgid "Effective" +msgstr "Effectif" + +#: ishtar_base/models.py:529 +msgid "Active" +msgstr "Actif" + +#: ishtar_base/models.py:530 +msgid "Field completed" +msgstr "Terrain achevé" + +#: ishtar_base/models.py:531 +msgid "Associated report" +msgstr "Rapport associé" + +#: ishtar_base/models.py:532 +msgid "Closed" +msgstr "Fermé" + +#: ishtar_base/models.py:533 +msgid "Documented and closed" +msgstr "Documenté et clôt" + +#: ishtar_base/models.py:983 ishtar_base/models.py:1044 +#: templates/dashboard_main.html:72 templates/dashboard_operation.html:17 +#: templates/dashboard_operation.html:113 +#: templates/dashboard_operation.html:302 +#: templates/dashboard_operation.html:334 +#: templates/dashboard_operation.html:485 +msgid "Number" +msgstr "Nombre" + +#: ishtar_base/models.py:1047 +msgid "Departement" +msgstr "Département" + +#: ishtar_base/models.py:1048 +msgid "Departements" +msgstr "Départements" + +#: ishtar_base/models.py:1064 +msgid "Mobile phone" +msgstr "Téléphone portable" + +#: ishtar_base/models.py:1074 +msgid "Organization types" +msgstr "Types d'organisation" + +#: ishtar_base/models.py:1079 ishtar_base/models.py:1110 +#: ishtar_base/models.py:1169 templates/dashboard_operation.html:82 +#: templates/sheet_contextrecord.html:83 templates/sheet_file.html:70 +#: templates/sheet_file.html.py:91 templates/sheet_file.html:118 +#: templates/sheet_ope.html:85 templates/sheet_ope.html.py:105 +#: templates/sheet_ope.html:126 templates/sheet_ope_modif.html:85 +#: templates/sheet_ope_modif.html.py:105 templates/sheet_ope_modif.html:126 +#: templates/sheet_operation.html:85 templates/sheet_operation.html.py:105 +#: templates/sheet_operation.html:125 +msgid "Type" +msgstr "Type" + +#: ishtar_base/models.py:1082 templates/dashboard_operation.html:216 +#: templates/dashboard_operation.html:405 +#: templates/dashboard_operation.html:424 +msgid "Organization" +msgstr "Organisation" + +#: ishtar_base/models.py:1083 +msgid "Organizations" +msgstr "Organisations" + +#: ishtar_base/models.py:1085 +msgid "Can view own Organization" +msgstr "Peut voir sa propre Organisation" + +#: ishtar_base/models.py:1086 +msgid "Can add own Organization" +msgstr "Peut ajouter sa propre Organisation" + +#: ishtar_base/models.py:1087 +msgid "Can change own Organization" +msgstr "Peut changer sa propre Organisation" + +#: ishtar_base/models.py:1088 +msgid "Can delete own Organization" +msgstr "Peut supprimer sa propre Organisation" + +#: ishtar_base/models.py:1095 +msgid "Rights" +msgstr "Droits" + +#: ishtar_base/models.py:1098 +msgid "Person types" +msgstr "Types d'individu" + +#: ishtar_base/models.py:1101 +msgid "Mr" +msgstr "M" + +#: ishtar_base/models.py:1102 +msgid "Miss" +msgstr "Mlle" + +#: ishtar_base/models.py:1103 +msgid "Mrs" +msgstr "Mme" + +#: ishtar_base/models.py:1104 +msgid "Doctor" +msgstr "Dr" + +#: ishtar_base/models.py:1112 +msgid "Is attached to" +msgstr "Est rattaché à" + +#: ishtar_base/models.py:1116 +msgid "Persons" +msgstr "Individus" + +#: ishtar_base/models.py:1118 +msgid "Can view Person" +msgstr "Peut voir les Personnes" + +#: ishtar_base/models.py:1119 +msgid "Can view own Person" +msgstr "Peut voir sa propre Personne" + +#: ishtar_base/models.py:1120 +msgid "Can add own Person" +msgstr "Peut ajouter sa propre Personne" + +#: ishtar_base/models.py:1121 +msgid "Can change own Person" +msgstr "Peut changer sa propre Personne" + +#: ishtar_base/models.py:1122 +msgid "Can delete own Person" +msgstr "Peut supprimer sa propre Personne" + +#: ishtar_base/models.py:1143 +msgid "Ishtar user" +msgstr "Utilisateur d'Ishtar" + +#: ishtar_base/models.py:1144 +msgid "Ishtar users" +msgstr "Utilisateurs d'Ishtar" + +#: ishtar_base/models.py:1149 +msgid "Author types" +msgstr "Types d'auteur" + +#: ishtar_base/models.py:1165 +msgid "Source types" +msgstr "Types de source" + +#: ishtar_base/models.py:1187 +msgid "Archaeological file type" +msgstr "Type de dossier archéologique" + +#: ishtar_base/models.py:1188 +msgid "Archaeological file types" +msgstr "Types de dossier archéologique" + +#: ishtar_base/models.py:1202 +msgid "Permit types" +msgstr "Types de permis" + +#: ishtar_base/models.py:1206 +msgid "Delay (in days)" +msgstr "Delai (en jours)" + +#: ishtar_base/models.py:1242 +msgid "Reference number" +msgstr "Référence" + +#: ishtar_base/models.py:1260 +msgid "Can view own Archaelogical file" +msgstr "Peut voir son propre Dossier archéologique" + +#: ishtar_base/models.py:1261 +msgid "Can add own Archaelogical file" +msgstr "Peut ajouter son propre Dossier archéologique" + +#: ishtar_base/models.py:1262 +msgid "Can change own Archaelogical file" +msgstr "Peut changer son propre Dossier archéologique" + +#: ishtar_base/models.py:1263 +msgid "Can delete own Archaelogical file" +msgstr "Peut supprimer son propre Dossier archéologique" + +#: ishtar_base/models.py:1281 ishtar_base/models.py:1422 +msgid "Intercommunal" +msgstr "Intercommunal" + +#: ishtar_base/models.py:1336 ishtar_base/models.py:1374 +#: ishtar_base/models.py:1549 +msgid "File" +msgstr "Dossier" + +#: ishtar_base/models.py:1337 ishtar_base/models.py:1531 +#: templates/dashboard_operation.html:273 +#: templates/dashboard_operation.html:286 +#: templates/dashboard_operation.html:456 +#: templates/dashboard_operation.html:469 +msgid "Department" +msgstr "Département" + +#: ishtar_base/models.py:1346 +msgid "Operation types" +msgstr "Types d'opération" + +#: ishtar_base/models.py:1370 templates/sheet_file.html:92 +msgid "In charge" +msgstr "Responsable" + +#: ishtar_base/models.py:1377 ishtar_base/models.py:2083 +msgid "Surface (m²)" +msgstr "Area (m²)" + +#: ishtar_base/models.py:1415 +msgid "Can view own Operation" +msgstr "Peut voir sa propre Opération" + +#: ishtar_base/models.py:1416 +msgid "Can add own Operation" +msgstr "Peut ajouter sa propre Opération" + +#: ishtar_base/models.py:1417 +msgid "Can change own Operation" +msgstr "Peut changer sa propre Opération" + +#: ishtar_base/models.py:1418 +msgid "Can delete own Operation" +msgstr "Peut supprimer sa propre Opération" + +#: ishtar_base/models.py:1463 +msgid "This operation code already exists for this year" +msgstr "Cet code d'opération existe déjà pour cette année." + +#: ishtar_base/models.py:1539 +msgid "Operation documentation" +msgstr "Documentation d'une opération" + +#: ishtar_base/models.py:1540 +msgid "Operation documentations" +msgstr "Documentations des opérations" + +#: ishtar_base/models.py:1579 +msgid "Parent period" +msgstr "Période parente" + +#: ishtar_base/models.py:1583 +msgid "Type Period" +msgstr "Type de période" + +#: ishtar_base/models.py:1584 +msgid "Types Period" +msgstr "Types de période" + +#: ishtar_base/models.py:1592 +msgid "Dating types" +msgstr "Types de datation" + +#: ishtar_base/models.py:1596 +msgid "Dating quality" +msgstr "Qualité de datation" + +#: ishtar_base/models.py:1597 +msgid "Dating qualities" +msgstr "Qualités de datation" + +#: ishtar_base/models.py:1610 +msgid "Datings" +msgstr "Datations" + +#: ishtar_base/models.py:1621 +msgid "Parent unit" +msgstr "Unité parente" + +#: ishtar_base/models.py:1625 +msgid "Type Unit" +msgstr "Type d'unité" + +#: ishtar_base/models.py:1626 +msgid "Types Unit" +msgstr "Types d'unité" + +#: ishtar_base/models.py:1635 +msgid "Type Activity" +msgstr "Type d'activité" + +#: ishtar_base/models.py:1636 +msgid "Types Activity" +msgstr "Types d'activités" + +#: ishtar_base/models.py:1644 +msgid "Type Identification" +msgstr "Type d'identification" + +#: ishtar_base/models.py:1645 +msgid "Types Identification" +msgstr "Types d'identification" + +#: ishtar_base/models.py:1668 +msgid "A short description of the location of the context record" +msgstr "Une courte description de la situation de l'Unité d'Enregistrement" + +#: ishtar_base/models.py:1678 +msgid "" +"\"Terminus Ante Quem\" the context record can't have been created after this " +"date" +msgstr "" +"« Terminus Ante Quem » l'Unité d'Enregistrement ne peut avoir été crée après " +"cette date" + +#: ishtar_base/models.py:1681 +msgid "Estimation of a \"Terminus Ante Quem\"" +msgstr "Estimation d'un « Terminus Ante Quem »" + +#: ishtar_base/models.py:1683 +msgid "" +"\"Terminus Post Quem\" the context record can't have been created before " +"this date" +msgstr "" +"« Terminus Post Quem » l'Unité d'Enregistrement ne peut avoir été crée avant " +"cette date" + +#: ishtar_base/models.py:1686 +msgid "Estimation of a \"Terminus Post Quem\"" +msgstr "Estimation d'un « Terminus Post Quem »" + +#: ishtar_base/models.py:1694 ishtar_base/models.py:1695 +#: ishtar_base/models.py:1773 templates/sheet_contextrecord.html:6 +msgid "Context Record" +msgstr "Unité d'Enregistrement" + +#: ishtar_base/models.py:1697 +msgid "Can view own Context Record" +msgstr "Peut voir sa propre Unité d'Enregistrement" + +#: ishtar_base/models.py:1698 +msgid "Can add own Context Record" +msgstr "Peut ajouter sa propre Unité d'Enregistrement" + +#: ishtar_base/models.py:1699 +msgid "Can change own Context Record" +msgstr "Peut changer sa propre Unité d'Enregistrement" + +#: ishtar_base/models.py:1700 +msgid "Can delete own Context Record" +msgstr "Peut supprimer sa propre Unité d'Enregistrement" + +#: ishtar_base/models.py:1755 +msgid "Context record documentation" +msgstr "Documentation d'une Unité d'Enregistrement" + +#: ishtar_base/models.py:1756 +msgid "Context record documentations" +msgstr "Documentations des Unités d'Enregistrement" + +#: ishtar_base/models.py:1761 +msgid "Recommendation" +msgstr "Recommendation" + +#: ishtar_base/models.py:1763 +msgid "Parent material" +msgstr "Matériau parent" + +#: ishtar_base/models.py:1767 +msgid "Material types" +msgstr "Types de matériaux" + +#: ishtar_base/models.py:1781 ishtar_base/models.py:1840 +msgid "Base item" +msgstr "Mobilier de base" + +#: ishtar_base/models.py:1782 +msgid "Base items" +msgstr "Mobiliers de base" + +#: ishtar_base/models.py:1784 +msgid "Can view own Base item" +msgstr "Peut voir son propre Mobilier de base" + +#: ishtar_base/models.py:1785 +msgid "Can add own Base item" +msgstr "Peut ajouter son propre Mobilier de base" + +#: ishtar_base/models.py:1786 +msgid "Can change own Base item" +msgstr "Peut changer son propre Mobilier de base" + +#: ishtar_base/models.py:1787 +msgid "Can delete own Base item" +msgstr "Peut supprimer son propre Mobilier de base" + +#: ishtar_base/models.py:1851 +msgid "Upstream treatment" +msgstr "Traitement amont" + +#: ishtar_base/models.py:1853 +msgid "Downstream treatment" +msgstr "Traitement aval" + +#: ishtar_base/models.py:1915 +msgid "Can view own Item" +msgstr "Peut voir son propre Mobilier" + +#: ishtar_base/models.py:1916 +msgid "Can add own Item" +msgstr "Peut ajouter son propre Mobilier" + +#: ishtar_base/models.py:1917 +msgid "Can change own Item" +msgstr "Peut changer son propre Mobilier" + +#: ishtar_base/models.py:1918 +msgid "Can delete own Item" +msgstr "Peut supprimer son propre Mobilier" + +#: ishtar_base/models.py:1944 +msgid "Item documentation" +msgstr "Documentation du mobilier" + +#: ishtar_base/models.py:1945 +msgid "Item documentations" +msgstr "Documentations des mobiliers" + +#: ishtar_base/models.py:1950 templates/sheet_ope.html:64 +#: templates/sheet_ope_modif.html:64 +msgid "Owner" +msgstr "Propriétaire" + +#: ishtar_base/models.py:1956 +msgid "Parcel owner" +msgstr "Propriétaire de parcelle" + +#: ishtar_base/models.py:1957 +msgid "Parcel owners" +msgstr "Propriétaires de parcelle" + +#: ishtar_base/models.py:1965 +msgid "Warehouse types" +msgstr "Types de dépôts" + +#: ishtar_base/models.py:1977 +msgid "Warehouses" +msgstr "Dépôts" + +#: ishtar_base/models.py:1979 +msgid "Can view own Warehouse" +msgstr "Peut voir son propre Dépôt" + +#: ishtar_base/models.py:1980 +msgid "Can add own Warehouse" +msgstr "Peut ajouter son propre Dépôt" + +#: ishtar_base/models.py:1981 +msgid "Can change own Warehouse" +msgstr "Peut changer son propre Dépôt" + +#: ishtar_base/models.py:1982 +msgid "Can delete own Warehouse" +msgstr "Peut supprimer son propre Dépôt" + +#: ishtar_base/models.py:1992 +msgid "Intended to" +msgstr "Destiné à" + +#: ishtar_base/models.py:1996 +msgid "Act types" +msgstr "Types d'acte" + +#: ishtar_base/models.py:2007 +msgid "Archaeological preventive operator" +msgstr "Opérateur d'archéologie préventive" + +#: ishtar_base/models.py:2009 +msgid "Person in charge of the scientific part" +msgstr "Responsable scientifique" + +#: ishtar_base/models.py:2025 +msgid "Administrative acts" +msgstr "Actes administratifs" + +#: ishtar_base/models.py:2027 +msgid "Can view own Administrative act" +msgstr "Peut voir son propre Acte administratif" + +#: ishtar_base/models.py:2028 +msgid "Can add own Administrative act" +msgstr "Peut ajouter son propre Acte administratif" + +#: ishtar_base/models.py:2029 +msgid "Can change own Administrative act" +msgstr "Peut changer son propre Acte administratif" + +#: ishtar_base/models.py:2030 +msgid "Can delete own Administrative act" +msgstr "Peut supprimer son propre Acte administratif" + +#: ishtar_base/models.py:2039 +msgid "Length (mm)" +msgstr "Longueur (mm) :" + +#: ishtar_base/models.py:2040 +msgid "Width (mm)" +msgstr "Largeur (mm) :" + +#: ishtar_base/models.py:2041 +msgid "Height (mm)" +msgstr "Hauteur (mm)" + +#: ishtar_base/models.py:2047 +msgid "Container types" +msgstr "Types de contenant" + +#: ishtar_base/models.py:2059 +msgid "Containers" +msgstr "Contenants" + +#: ishtar_base/models.py:2084 templates/sheet_contextrecord.html:71 +#: templates/sheet_file.html:43 templates/sheet_ope.html:46 +#: templates/sheet_ope.html.py:107 templates/sheet_ope_modif.html:46 +#: templates/sheet_ope_modif.html.py:107 templates/sheet_operation.html:46 +msgid "Localisation" +msgstr "Localisation" + +#: ishtar_base/models.py:2107 +msgid "Virtual" +msgstr "Virtuel" + +#: ishtar_base/models.py:2110 +msgid "Treatment types" +msgstr "Types de traitements" + +#: ishtar_base/models.py:2127 ishtar_base/models.py:2146 +msgid "Treatment" +msgstr "Traitement" + +#: ishtar_base/models.py:2128 +msgid "Treatments" +msgstr "Traitements" + +#: ishtar_base/models.py:2130 +msgid "Can view own Treatment" +msgstr "Peut voir son propre Traitement" + +#: ishtar_base/models.py:2131 +msgid "Can add own Treatment" +msgstr "Peut ajouter son propre Traitement" + +#: ishtar_base/models.py:2132 +msgid "Can change own Treatment" +msgstr "Peut changer son propre Traitement" + +#: ishtar_base/models.py:2133 +msgid "Can delete own Treatment" +msgstr "Peut supprimer son propre traitement" + +#: ishtar_base/models.py:2139 templates/sheet_contextrecord.html:65 +#: templates/sheet_file.html:35 templates/sheet_ope.html:22 +#: templates/sheet_ope_modif.html:22 templates/sheet_operation.html:22 +msgid "by" +msgstr "par" + +#: ishtar_base/models.py:2144 +msgid "Treatment documentation" +msgstr "Documentation d'un traitement" + +#: ishtar_base/models.py:2145 +msgid "Treament documentations" +msgstr "Documentations des traitements" + +#: ishtar_base/models.py:2158 +msgid "Property" +msgstr "Propriété" + +#: ishtar_base/models.py:2159 +msgid "Properties" +msgstr "Propriétés" + +#: ishtar_base/views.py:158 +msgid "True" +msgstr "Oui" + +#: ishtar_base/views.py:160 +msgid "False" +msgstr "Non" + +#: ishtar_base/views.py:290 templates/sheet_contextrecord.html:127 +#: templates/sheet_file.html:106 templates/sheet_ope.html:139 +#: templates/sheet_ope_modif.html:139 templates/sheet_ope_modif.html.py:175 +#: templates/sheet_operation.html:138 templates/sheet_operation.html.py:171 +msgid "Details" +msgstr "Détails" + +#: ishtar_base/views.py:642 ishtar_base/views.py:676 +msgid "Operation not permitted." +msgstr "Opération non permise" + +#: ishtar_base/views.py:645 +#, python-format +msgid "New %s" +msgstr "Nouveau %s" + +#: ishtar_base/views.py:697 templates/sheet_operation.html:122 +msgid "Context records" +msgstr "Unité d'Enregistrement" + +#: ishtar_base/views.py:698 +msgid "Archaeological items" +msgstr "Mobilier" + +#: ishtar_base/widgets.py:40 +msgid "Delete" +msgstr "Supprimer" + +#: ishtar_base/widgets.py:218 +msgid "Search and select an item" +msgstr "Rechercher puis sélectionner un élément" + +#: ishtar_base/widgets.py:253 ishtar_base/widgets.py:258 +msgid "Export as CSV" +msgstr "Export en CSV" + +#: ishtar_base/widgets.py:254 +msgid "simple" +msgstr "simple" + +#: ishtar_base/widgets.py:255 +msgid "full" +msgstr "complet" + +#: ishtar_base/widgets.py:271 +msgid "No results" +msgstr "Pas de résultats" + +#: ishtar_base/widgets.py:272 +msgid "Loading..." +msgstr "Chargement..." + +#: ishtar_base/widgets.py:273 +msgid "Remove" +msgstr "Enlever" + +#: templates/base.html:26 +msgid "Logged in" +msgstr "Connecté" + +#: templates/base.html:27 +msgid "Log out" +msgstr "Déconnexion" + +#: templates/base.html:28 +msgid "Change password" +msgstr "Changement de mot de passe" + +#: templates/base.html:30 templates/registration/activate.html:10 +#: templates/registration/login.html:8 templates/registration/login.html:10 +#: templates/registration/password_reset_complete.html:8 +msgid "Log in" +msgstr "Connexion" + +#: templates/base.html:42 +msgid "Default items" +msgstr "Éléments par défaut" + +#: templates/confirm_wizard.html:13 templates/wizard_done_summary.html:6 +msgid "You have entered the following informations:" +msgstr "Vous avez entré les informations suivantes :" + +#: templates/confirm_wizard.html:27 +msgid "Would you like to save them?" +msgstr "Voulez vous sauver ces informations ?" + +#: templates/confirm_wizard.html:30 templates/default_wizard.html:22 +#: templates/default_wizard.html.py:38 templates/search.html:13 +#: templates/towns_wizard.html:18 templates/towns_wizard.html.py:37 +msgid "Validate" +msgstr "Valider" + +#: templates/dashboard_file.html:11 templates/dashboard_operation.html:11 +msgid "Global informations" +msgstr "Informations générales" + +#: templates/dashboard_file.html:13 templates/dashboard_file.html.py:46 +#: templates/dashboard_file.html:100 templates/dashboard_main.html:13 +msgid "Total:" +msgstr "Total :" + +#: templates/dashboard_file.html:15 +msgid ":" +msgstr " :" + +#: templates/dashboard_file.html:19 templates/dashboard_file.html.py:49 +#: templates/dashboard_file.html:128 templates/dashboard_operation.html:54 +#: templates/dashboard_operation.html:124 +#: templates/dashboard_operation.html:345 +msgid "By year" +msgstr "Par année" + +#: templates/dashboard_file.html:31 templates/dashboard_file.html.py:61 +#: templates/dashboard_file.html:140 templates/dashboard_operation.html:258 +#: templates/dashboard_operation.html:441 +msgid "By month" +msgstr "Par mois" + +#: templates/dashboard_file.html:44 +msgid "Research archaeology" +msgstr "Archéologie programmée" + +#: templates/dashboard_file.html:73 templates/dashboard_file.html.py:167 +#: templates/dashboard_operation.html:271 +#: templates/dashboard_operation.html:454 +msgid "By department" +msgstr "Par département" + +#: templates/dashboard_file.html:85 +msgid "Main towns" +msgstr "Principales communes" + +#: templates/dashboard_file.html:98 +msgid "Rescue archaeology" +msgstr "Archéologie préventive" + +#: templates/dashboard_file.html:104 +msgid "By saisine type" +msgstr "Par type de saisine" + +#: templates/dashboard_file.html:116 +msgid "By administrative act" +msgstr "Par acte administratif" + +#: templates/dashboard_file.html:150 +msgid "Archaeological files linked to at least one operation:" +msgstr "Dossier archéologique associé au moins à une opération :" + +#: templates/dashboard_file.html:151 +msgid "Archaeological files linked to at least one operation (%):" +msgstr "Dossier archéologique associé au moins à une opération (%) :" + +#: templates/dashboard_file.html:155 +msgid "Archaeological files linked to at least one operation (%)" +msgstr "Dossier archéologique associé au moins à une opération (%)" + +#: templates/dashboard_file.html:179 +msgid "Surface by department (m²)" +msgstr "Surface par département (m²)" + +#: templates/dashboard_file.html:191 templates/dashboard_operation.html:300 +#: templates/dashboard_operation.html:483 +msgid "Main towns by number" +msgstr "Principales communes en nombre" + +#: templates/dashboard_file.html:203 +msgid "Main towns by surface (m²)" +msgstr "Principales communes en surface (m²)" + +#: templates/dashboard_main.html:12 templates/sheet_contextrecord.html:108 +#: templates/sheet_ope_modif.html:156 templates/sheet_operation.html:154 +msgid "Numbers" +msgstr "Nombre" + +#: templates/dashboard_main.html:25 +msgid "By years" +msgstr "Par années" + +#: templates/dashboard_main.html:27 templates/dashboard_main.html.py:37 +msgid "Average:" +msgstr "Moyenne :" + +#: templates/dashboard_main.html:28 templates/dashboard_main.html.py:38 +msgid "Variance:" +msgstr "Variance :" + +#: templates/dashboard_main.html:29 templates/dashboard_main.html.py:39 +msgid "Standard deviation:" +msgstr "Écart-type :" + +#: templates/dashboard_main.html:30 templates/dashboard_main.html.py:40 +msgid "Median:" +msgstr "Médiane :" + +#: templates/dashboard_main.html:31 templates/dashboard_main.html.py:41 +msgid "Mode:" +msgstr "Mode :" + +#: templates/dashboard_main.html:35 +msgid "By operations" +msgstr "Par opérations" + +#: templates/dashboard_main.html:44 +msgid "Created last" +msgstr "Derniers créés" + +#: templates/dashboard_main.html:47 +msgid "Created" +msgstr "Créé" + +#: templates/dashboard_main.html:51 templates/dashboard_main.html.py:62 +msgid "Show" +msgstr "Voir" + +#: templates/dashboard_main.html:55 +msgid "Recent changes" +msgstr "Derniers changés" + +#: templates/dashboard_main.html:58 +msgid "Modified" +msgstr "Modifier" + +#: templates/dashboard_main.html:69 +msgid "Users" +msgstr "Utilisateurs" + +#: templates/dashboard_main.html:72 +msgid "User type" +msgstr "Type d'utilisateur" + +#: templates/dashboard_operation.html:15 +#: templates/dashboard_operation.html:111 +#: templates/dashboard_operation.html:332 +msgid "Total" +msgstr "Total" + +#: templates/dashboard_operation.html:17 templates/dashboard_operation.html:30 +#: templates/dashboard_operation.html:113 +#: templates/dashboard_operation.html:152 +#: templates/dashboard_operation.html:184 +#: templates/dashboard_operation.html:334 +#: templates/dashboard_operation.html:373 +msgid "Status" +msgstr "État" + +#: templates/dashboard_operation.html:28 +msgid "Area by type of operation" +msgstr "Surface par type d'opération" + +#: templates/dashboard_operation.html:30 +msgid "Area (m²)" +msgstr "Surface (m²)" + +#: templates/dashboard_operation.html:41 +msgid "By types" +msgstr "Par types" + +#: templates/dashboard_operation.html:43 templates/dashboard_operation.html:56 +#: templates/dashboard_operation.html:69 templates/dashboard_operation.html:95 +#: templates/dashboard_operation.html:126 +#: templates/dashboard_operation.html:139 +#: templates/dashboard_operation.html:260 +#: templates/dashboard_operation.html:347 +#: templates/dashboard_operation.html:360 +#: templates/dashboard_operation.html:443 +msgid "State" +msgstr "État" + +#: templates/dashboard_operation.html:67 +#: templates/dashboard_operation.html:137 +#: templates/dashboard_operation.html:358 +msgid "By realisation year" +msgstr "Par année de réalisation" + +#: templates/dashboard_operation.html:80 +msgid "Effective operation by type and year" +msgstr "Opération effective par type et année" + +#: templates/dashboard_operation.html:93 +msgid "By realisation month" +msgstr "Par mois de réalisation" + +#: templates/dashboard_operation.html:107 +msgid "Survey informations" +msgstr "Informations : diagnostics" + +#: templates/dashboard_operation.html:150 +msgid "Current year" +msgstr "Année en cours" + +#: templates/dashboard_operation.html:155 +#: templates/dashboard_operation.html:171 +#: templates/dashboard_operation.html:187 +#: templates/dashboard_operation.html:203 +#: templates/dashboard_operation.html:289 +#: templates/dashboard_operation.html:376 +#: templates/dashboard_operation.html:392 +msgid "Area" +msgstr "Surface" + +#: templates/dashboard_operation.html:158 +#: templates/dashboard_operation.html:171 +#: templates/dashboard_operation.html:190 +#: templates/dashboard_operation.html:203 +#: templates/dashboard_operation.html:379 +#: templates/dashboard_operation.html:392 +msgid "Man-day" +msgstr "Jour-homme" + +#: templates/dashboard_operation.html:161 +#: templates/dashboard_operation.html:171 +#: templates/dashboard_operation.html:193 +#: templates/dashboard_operation.html:203 +#: templates/dashboard_operation.html:382 +#: templates/dashboard_operation.html:392 +msgid "Man-day/hectare" +msgstr "Jour-homme/hectare" + +#: templates/dashboard_operation.html:165 +msgid "Man-day/hectare for effective operations (current year):" +msgstr "Jour-homme/hectare pour les opération effectives (année en cours) :" + +#: templates/dashboard_operation.html:169 +msgid "Organizations (current year)" +msgstr "Organisations (année en cours)" + +#: templates/dashboard_operation.html:182 +#: templates/dashboard_operation.html:371 +msgid "Current realisation year" +msgstr "Année actuelle (réalisations)" + +#: templates/dashboard_operation.html:197 +#: templates/dashboard_operation.html:386 +msgid "Man-day/hectare for effective operations (current realisation year):" +msgstr "" +"Jour-homme/hectare pour les opération effectives (année de réalisation en " +"cours) :" + +#: templates/dashboard_operation.html:201 +#: templates/dashboard_operation.html:390 +msgid "Organizations (current realisation year)" +msgstr "Organisations (année de réalisation en cours)" + +#: templates/dashboard_operation.html:214 +#: templates/dashboard_operation.html:403 +msgid "Area by organization by year" +msgstr "Surface par organisation et par année" + +#: templates/dashboard_operation.html:224 +#: templates/dashboard_operation.html:416 +#: templates/dashboard_operation.html:435 +msgid "Mean" +msgstr "Moyenne" + +#: templates/dashboard_operation.html:230 +msgid "Effective operations areas (m²)" +msgstr "Surface des opérations en cours (m²)" + +#: templates/dashboard_operation.html:235 +#: templates/dashboard_operation.html:273 +#: templates/dashboard_operation.html:286 +#: templates/dashboard_operation.html:413 +#: templates/dashboard_operation.html:432 +#: templates/dashboard_operation.html:456 +#: templates/dashboard_operation.html:469 +msgid "Sum" +msgstr "Somme" + +#: templates/dashboard_operation.html:238 +#: templates/dashboard_operation.html:252 +msgid "Average" +msgstr "Moyenne" + +#: templates/dashboard_operation.html:244 +msgid "Man-Days/hectare by Year" +msgstr "Jours-homme/hectare par année" + +#: templates/dashboard_operation.html:249 +msgid "Man-Days/hectare" +msgstr "Jours-homme/hectare" + +#: templates/dashboard_operation.html:284 +#: templates/dashboard_operation.html:467 +msgid "Effective operation by department" +msgstr "Opérations effectives par départements" + +#: templates/dashboard_operation.html:289 +#: templates/dashboard_operation.html:472 +msgid "Nb." +msgstr "Nb." + +#: templates/dashboard_operation.html:313 +msgid "Main towns by surface" +msgstr "Principales communes en surface" + +#: templates/dashboard_operation.html:328 +msgid "Excavation informations" +msgstr "Fouilles : informations" + +#: templates/dashboard_operation.html:422 +msgid "Area by organization by realisation year" +msgstr "Surface par organisation et par année de réalisation" + +#: templates/dashboard_operation.html:472 +msgid "Cost" +msgstr "Coût" + +#: templates/dashboard_operation.html:472 +msgid "FNAP cost" +msgstr "Coût FNAP" + +#: templates/dashboard_operation.html:496 +msgid "Main towns by cost" +msgstr "Principales communes par coût" + +#: templates/default_wizard.html:29 templates/search.html:20 +#: templates/towns_wizard.html:25 +msgid "Add/Modify" +msgstr "Ajouter-Modifier" + +#: templates/default_wizard.html:39 +msgid "Validate and end" +msgstr "Valider et confirmer" + +#: templates/form_snippet.html:9 +msgid "Help" +msgstr "Aide" + +#: templates/sheet.html:19 +msgid "Close" +msgstr "Fermer" + +#: templates/sheet.html:21 +msgid "Close all windows" +msgstr "Fermer toutes les fenêtres" + +#: templates/sheet_contextrecord.html:4 templates/sheet_file.html:16 +#: templates/sheet_ope.html:4 templates/sheet_ope_modif.html:4 +#: templates/sheet_operation.html:4 +msgid "Export as:" +msgstr "Export en :" + +#: templates/sheet_contextrecord.html:4 templates/sheet_file.html:16 +#: templates/sheet_ope.html:4 templates/sheet_ope_modif.html:4 +#: templates/sheet_operation.html:4 +msgid "OpenOffice.org file" +msgstr "fichier OpenOffice.org" + +#: templates/sheet_contextrecord.html:4 templates/sheet_file.html:16 +#: templates/sheet_ope.html:4 templates/sheet_ope_modif.html:4 +#: templates/sheet_operation.html:4 +msgid "PDF file" +msgstr "fichier PDF" + +#: templates/sheet_contextrecord.html:9 +msgid "Complete ID:" +msgstr "Identifiant complet :" + +#: templates/sheet_contextrecord.html:11 templates/sheet_contextrecord.html:54 +#: templates/sheet_operation.html:10 +msgid "Patriarche OA code not yet recorded!" +msgstr "Code Patriarche pas encore enregistré !" + +#: templates/sheet_contextrecord.html:12 +msgid "Temporary ID:" +msgstr "Identifiant temporaire :" + +#: templates/sheet_contextrecord.html:16 templates/sheet_contextrecord.html:67 +#: templates/sheet_file.html:38 templates/sheet_ope.html:24 +#: templates/sheet_ope_modif.html:24 templates/sheet_operation.html:24 +msgid "Type:" +msgstr "Type :" + +#: templates/sheet_contextrecord.html:18 +msgid "Chronology:" +msgstr "Chronologie :" + +#: templates/sheet_contextrecord.html:19 +msgid "Place:" +msgstr "Lieu :" + +#: templates/sheet_contextrecord.html:20 +msgid "Parcel:" +msgstr "Parcelle :" + +#: templates/sheet_contextrecord.html:25 +msgid "Description:" +msgstr "Description :" + +#: templates/sheet_contextrecord.html:26 +msgid "Length (cm):" +msgstr "Longueur (cm) :" + +#: templates/sheet_contextrecord.html:27 +msgid "Width (cm):" +msgstr "Largeur (cm) :" + +#: templates/sheet_contextrecord.html:28 +msgid "Depth (cm):" +msgstr "Profondeur (cm) :" + +#: templates/sheet_contextrecord.html:34 +msgid "Activity:" +msgstr "Activité :" + +#: templates/sheet_contextrecord.html:35 +msgid "Identification:" +msgstr "Identification :" + +#: templates/sheet_contextrecord.html:36 +msgid "Interpretation:" +msgstr "Interpretation :" + +#: templates/sheet_contextrecord.html:40 +msgid "Datations" +msgstr "Datations" + +#: templates/sheet_contextrecord.html:41 +msgid "TAQ:" +msgstr "TAQ :" + +#: templates/sheet_contextrecord.html:42 +msgid "TAQ estimated:" +msgstr "TAQ estimé :" + +#: templates/sheet_contextrecord.html:43 +msgid "TPQ:" +msgstr "TPQ :" + +#: templates/sheet_contextrecord.html:44 +msgid "TPQ estimated:" +msgstr "TPQ estimé :" + +#: templates/sheet_contextrecord.html:48 +msgid "Operation resume" +msgstr "Résumé de l'opération" + +#: templates/sheet_contextrecord.html:49 templates/sheet_file.html:18 +#: templates/sheet_ope.html:6 templates/sheet_ope_modif.html:6 +#: templates/sheet_operation.html:6 +msgid "Year:" +msgstr "Année :" + +#: templates/sheet_contextrecord.html:50 templates/sheet_file.html:19 +#: templates/sheet_ope.html:7 templates/sheet_ope_modif.html:7 +#: templates/sheet_operation.html:7 +msgid "Numerical reference:" +msgstr "Référence numérique :" + +#: templates/sheet_contextrecord.html:52 templates/sheet_ope.html:9 +#: templates/sheet_ope_modif.html:9 templates/sheet_operation.html:9 +msgid "Patriarche OA code:" +msgstr "Code Patriarche :" + +#: templates/sheet_contextrecord.html:57 templates/sheet_ope.html:19 +#: templates/sheet_ope_modif.html:19 templates/sheet_operation.html:19 +msgid "Head scientist:" +msgstr "Responsable scientifique :" + +#: templates/sheet_contextrecord.html:59 templates/sheet_file.html:33 +#: templates/sheet_ope.html:20 templates/sheet_ope_modif.html:20 +#: templates/sheet_operation.html:20 +msgid "State:" +msgstr "État :" + +#: templates/sheet_contextrecord.html:61 templates/sheet_file.html:33 +#: templates/sheet_ope.html:20 templates/sheet_ope_modif.html:20 +#: templates/sheet_operation.html:20 +msgid "Active file" +msgstr "Dossier archéologique actif" + +#: templates/sheet_contextrecord.html:63 templates/sheet_ope.html:21 +#: templates/sheet_ope_modif.html:21 templates/sheet_operation.html:21 +msgid "Closed operation" +msgstr "Opération fermée" + +#: templates/sheet_contextrecord.html:64 templates/sheet_file.html:35 +#: templates/sheet_ope.html:22 templates/sheet_ope_modif.html:22 +#: templates/sheet_operation.html:22 +msgid "Closing date:" +msgstr "Date de clotûre :" + +#: templates/sheet_contextrecord.html:68 templates/sheet_ope.html:29 +#: templates/sheet_ope_modif.html:29 templates/sheet_operation.html:29 +msgid "Remains:" +msgstr "Vestiges :" + +#: templates/sheet_contextrecord.html:69 templates/sheet_ope.html:30 +#: templates/sheet_ope_modif.html:30 templates/sheet_operation.html:30 +msgid "Periods:" +msgstr "Périodes :" + +#: templates/sheet_contextrecord.html:70 templates/sheet_file.html:41 +#: templates/sheet_ope.html:44 templates/sheet_ope_modif.html:44 +#: templates/sheet_operation.html:44 +msgid "Comment:" +msgstr "Commentaire :" + +#: templates/sheet_contextrecord.html:72 templates/sheet_file.html:44 +#: templates/sheet_ope.html:47 templates/sheet_ope_modif.html:47 +#: templates/sheet_operation.html:47 +msgid "Towns:" +msgstr "Communes :" + +#: templates/sheet_contextrecord.html:73 +msgid "Related operation:" +msgstr "Operation associée :" + +#: templates/sheet_contextrecord.html:76 +msgid "No operation linked to this context unit!" +msgstr "Pas d'opération associée à ce Unité d'Enregistrement" + +#: templates/sheet_contextrecord.html:80 templates/sheet_ope.html:102 +#: templates/sheet_ope_modif.html:102 templates/sheet_operation.html:102 +msgid "Documents" +msgstr "Documents" + +#: templates/sheet_contextrecord.html:95 +msgid "No document associated to this context record" +msgstr "Pas d'opération associée à cette Unité d'enregistrement" + +#: templates/sheet_contextrecord.html:100 templates/sheet_ope_modif.html:146 +#: templates/sheet_ope_modif.html.py:148 templates/sheet_operation.html:146 +msgid "Finds" +msgstr "Mobilier" + +#: templates/sheet_contextrecord.html:102 templates/sheet_operation.html:148 +msgid "Find" +msgstr "Mobilier" + +#: templates/sheet_contextrecord.html:107 templates/sheet_ope_modif.html:155 +#: templates/sheet_operation.html:153 +msgid "Weight" +msgstr "Poids" + +#: templates/sheet_contextrecord.html:131 +msgid "No find associated to this context record" +msgstr "Pas de mobilier associé à cette Unité d'Enregistrement" + +#: templates/sheet_file.html:7 +msgid "Previous version" +msgstr "Version précédente" + +#: templates/sheet_file.html:11 +msgid "Are you sure to rollback to this version?" +msgstr "" +"Voulez vous annuler les modifications faites pour revenir à cette version ?" + +#: templates/sheet_file.html:12 +msgid "Next version" +msgstr "Version suivante" + +#: templates/sheet_file.html:21 +msgid "File's name:" +msgstr "Nom du dossier archéologique :" + +#: templates/sheet_file.html:23 templates/sheet_ope.html:14 +#: templates/sheet_ope_modif.html:14 templates/sheet_operation.html:14 +msgid "Edition date:" +msgstr "Date d'édition :" + +#: templates/sheet_file.html:24 +msgid "Reception date:" +msgstr "Date de réception :" + +#: templates/sheet_file.html:25 +msgid "Creation date:" +msgstr "Date de création :" + +#: templates/sheet_file.html:28 +msgid "Deadline:" +msgstr "Date d'échéance :" + +#: templates/sheet_file.html:32 +msgid "In charge:" +msgstr "Responsable :" + +#: templates/sheet_file.html:34 +msgid "Closed file" +msgstr "Dossier archéologique clos" + +#: templates/sheet_file.html:40 templates/sheet_ope.html:33 +#: templates/sheet_ope_modif.html:33 +msgid "Related file:" +msgstr "Dossier en relation avec :" + +#: templates/sheet_file.html:46 templates/sheet_ope.html:49 +#: templates/sheet_ope_modif.html:49 templates/sheet_operation.html:49 +msgid "Main address:" +msgstr "Adresse principale :" + +#: templates/sheet_file.html:47 templates/sheet_ope.html:50 +#: templates/sheet_ope_modif.html:50 templates/sheet_operation.html:50 +msgid "Complement:" +msgstr "Complément :" + +#: templates/sheet_file.html:48 templates/sheet_ope.html:51 +#: templates/sheet_ope_modif.html:51 templates/sheet_operation.html:51 +msgid "Postal code:" +msgstr "Code postal :" + +#: templates/sheet_file.html:50 templates/sheet_ope.html:25 +#: templates/sheet_ope_modif.html:25 templates/sheet_operation.html:25 +msgid "Surface:" +msgstr "Surface :" + +#: templates/sheet_file.html:55 +msgid "Preventive archaelogical file" +msgstr "Dossier d'archéologie préventive" + +#: templates/sheet_file.html:56 +msgid "Planed surface:" +msgstr "Surface envisagé :" + +#: templates/sheet_file.html:57 +msgid "Saisine type:" +msgstr "Type de saisine :" + +#: templates/sheet_file.html:58 templates/sheet_ope.html:36 +#: templates/sheet_ope_modif.html:36 templates/sheet_operation.html:36 +msgid "Town planning service:" +msgstr "Service instructeur :" + +#: templates/sheet_file.html:59 templates/sheet_ope.html:37 +#: templates/sheet_ope_modif.html:37 templates/sheet_operation.html:37 +msgid "Permit type:" +msgstr "Type de permis :" + +#: templates/sheet_file.html:60 templates/sheet_ope.html:38 +#: templates/sheet_ope_modif.html:38 templates/sheet_operation.html:38 +msgid "Permit reference:" +msgstr "Référence du permis :" + +#: templates/sheet_file.html:61 templates/sheet_ope.html:39 +#: templates/sheet_ope_modif.html:39 templates/sheet_operation.html:39 +msgid "General contractor organisation:" +msgstr "Organisation de l'aménageur :" + +#: templates/sheet_file.html:62 templates/sheet_ope.html:40 +#: templates/sheet_ope_modif.html:40 templates/sheet_operation.html:40 +msgid "General contractor:" +msgstr "Aménageur :" + +#: templates/sheet_file.html:66 templates/sheet_ope.html:79 +#: templates/sheet_ope.html.py:81 templates/sheet_ope_modif.html:79 +#: templates/sheet_ope_modif.html.py:81 templates/sheet_operation.html:81 +msgid "Admninistrative acts" +msgstr "Actes administratifs" + +#: templates/sheet_file.html:81 +msgid "No administrative act associated to this archaelogical file" +msgstr "Pas d'acte administratif associé à ce dosser" + +#: templates/sheet_file.html:109 +msgid "No operation associated to this archaelogical file" +msgstr "Pas d'opération associée à ce dosser" + +#: templates/sheet_file.html:114 +msgid "Admninistrative acts linked to associated operations" +msgstr "Actes administratifs associés aux opérations" + +#: templates/sheet_file.html:129 +msgid "No administrative act linked to operations" +msgstr "Pas d'acte administratif associé aux opérations" + +#: templates/sheet_ope.html:10 templates/sheet_ope_modif.html:10 +msgid "Patriarche OA code not yet recorded !" +msgstr "Code Patriarche pas encore enregistré !" + +#: templates/sheet_ope.html:12 templates/sheet_ope_modif.html:12 +msgid "Operation's name:" +msgstr "Nom de l'opération" + +#: templates/sheet_ope.html:16 templates/sheet_ope_modif.html:16 +#: templates/sheet_operation.html:16 +msgid "Begining date:" +msgstr "Date de début :" + +#: templates/sheet_ope.html:17 templates/sheet_ope_modif.html:17 +msgid "Field work end date:" +msgstr "Date de fin de travail sur le terrain :" + +#: templates/sheet_ope.html:26 templates/sheet_ope_modif.html:26 +#: templates/sheet_operation.html:26 +msgid "Cost:" +msgstr "Coût :" + +#: templates/sheet_ope.html:27 templates/sheet_ope_modif.html:27 +#: templates/sheet_operation.html:27 +msgid "Duration:" +msgstr "Durée :" + +#: templates/sheet_ope.html:27 templates/sheet_ope_modif.html:27 +#: templates/sheet_operation.html:27 +msgid "Day" +msgstr "Jour" + +#: templates/sheet_ope.html:35 templates/sheet_ope_modif.html:35 +msgid "Operator's reference code:" +msgstr "Référence de l'opérateur :" + +#: templates/sheet_ope.html:53 templates/sheet_ope_modif.html:53 +#: templates/sheet_operation.html:54 +msgid "Lambert X:" +msgstr "Lambert X :" + +#: templates/sheet_ope.html:54 templates/sheet_ope_modif.html:54 +#: templates/sheet_operation.html:55 +msgid "Lambert Y:" +msgstr "Lambert Y :" + +#: templates/sheet_ope.html:55 templates/sheet_ope_modif.html:55 +#: templates/sheet_operation.html:56 +msgid "Altitude (m NGF):" +msgstr "Altitude (m NGF):" + +#: templates/sheet_ope.html:58 templates/sheet_ope_modif.html:58 +#: templates/sheet_operation.html:59 +msgid "Associated parcels" +msgstr "Parcelles associées" + +#: templates/sheet_ope.html:60 templates/sheet_ope_modif.html:60 +#: templates/sheet_operation.html:61 +msgid "Commune" +msgstr "Commune" + +#: templates/sheet_ope.html:75 templates/sheet_ope_modif.html:75 +#: templates/sheet_operation.html:76 +msgid "No parcel associated to this operation" +msgstr "Pas de parcelle associée à cette opération" + +#: templates/sheet_ope.html:96 templates/sheet_ope_modif.html:96 +msgid "No administrative act associated to this operation" +msgstr "Pas d'acte administratif associé aux opérations" + +#: templates/sheet_ope.html:117 templates/sheet_ope_modif.html:117 +msgid "No document associated to this operation" +msgstr "Pas d'opération associée à cette opération" + +#: templates/sheet_ope.html:121 templates/sheet_ope.html.py:123 +#: templates/sheet_ope_modif.html:121 templates/sheet_ope_modif.html.py:123 +msgid "Recording Units" +msgstr "Unités d'Enregistrement :" + +#: templates/sheet_ope.html:127 templates/sheet_ope_modif.html:127 +#: templates/sheet_operation.html:126 +msgid "Chronology" +msgstr "Chronologie" + +#: templates/sheet_ope.html:142 templates/sheet_ope_modif.html:142 +msgid "No recording unit associated to this operation" +msgstr "Pas d'Unité d'Enregistrement associée à ce dosser" + +#: templates/sheet_ope_modif.html:150 +msgid "Find_complete_Label" +msgstr "" + +#: templates/sheet_ope_modif.html:151 +msgid "Find_complete_material_type_Label" +msgstr "" + +#: templates/sheet_ope_modif.html:152 +msgid "Context_record" +msgstr "Unité d'Enregistrement" + +#: templates/sheet_ope_modif.html:163 +msgid "find.complete_label" +msgstr "" + +#: templates/sheet_ope_modif.html:164 +msgid "find.not_patriarche_complete_label" +msgstr "" + +#: templates/sheet_ope_modif.html:166 +msgid "find.material_type_complete_label" +msgstr "" + +#: templates/sheet_ope_modif.html:167 +msgid "find.material_type_not_patriarche_complete_label" +msgstr "" + +#: templates/sheet_ope_modif.html:178 +msgid "No find associated to this operation" +msgstr "Pas de mobilier associé à cette opération" + +#: templates/sheet_operation.html:17 +msgid "Excavation end date:" +msgstr "Date de fin de chantier :" + +#: templates/sheet_operation.html:33 +msgid "Associated file:" +msgstr "Dossier associé :" + +#: templates/sheet_operation.html:96 +msgid "No acts associated to this operation" +msgstr "Pas d'acte associé à cette opération" + +#: templates/sheet_operation.html:100 +msgid "Scientific documentation" +msgstr "Documentation scientifique" + +#: templates/sheet_operation.html:117 +msgid "No scientific document associated to this operation" +msgstr "Pas de documentation scientifique associée à cette opération" + +#: templates/sheet_operation.html:141 +msgid "No context record associated to this operation" +msgstr "Pas d'Unité d'Enregistrement associée à cette opération" + +#: templates/sheet_operation.html:175 +msgid "No find associated to context record" +msgstr "Pas de mobilier associé à cette Unité d'Enregistrement" + +#: templates/sheet_operation.html:178 +msgid "No find associated to parcel" +msgstr "Pas de mobilier associé à cette parcelle" + +#: templates/sheet_operation.html:178 +msgid "(no context record)" +msgstr "(pas d'Unité d'Enregistrement)" + +#: templates/towns_wizard.html:33 +msgid "No town set in the associated file." +msgstr "Pas de commune dans le dossier associé." + +#: templates/wizard_closing_done.html:4 +msgid "Item successfully closed" +msgstr "Élément clôt avec succès" + +#: templates/wizard_delete_done.html:4 +msgid "Item successfully deleted" +msgstr "Élément supprimé avec succès" + +#: templates/wizard_done.html:4 +msgid "Item successfully saved" +msgstr "Élément enregistré avec succès" + +#: templates/wizard_done_summary_2.html:7 +#: templates/wizard_list_search_result.html:9 +msgid "You have saved the following informations:" +msgstr "Vous avez enregistré les informations suivantes :" + +#: templates/admin/base_site.html:4 templates/admin/base_site.html.py:7 +msgid "Ishtar administration" +msgstr "Administration d'Ishtar" + +#: templates/registration/activate.html:8 +msgid "Account successfully activated" +msgstr "Compte crée avec succès" + +#: templates/registration/activate.html:14 +msgid "Account activation failed" +msgstr "La création du compte a échouée" + +#: templates/registration/login.html:16 +msgid "Forgot password?" +msgstr "Oubli de mot de passe ?" + +#: templates/registration/login.html:16 +msgid "Reset it" +msgstr "Réinitialiser" + +#: templates/registration/login.html:17 +msgid "Not member?" +msgstr "Non enregistré ?" + +#: templates/registration/login.html:17 +#: templates/registration/registration_form.html:8 +msgid "Register" +msgstr "S'enregistrer" + +#: templates/registration/logout.html:6 +msgid "Logged out" +msgstr "Déconnecté" + +#: templates/registration/password_change_done.html:6 +msgid "Password changed" +msgstr "Mot de passe changé" + +#: templates/registration/password_change_form.html:10 +#: templates/registration/password_reset_confirm.html:11 +#: templates/registration/password_reset_form.html:11 +#: templates/registration/registration_form.html:10 +msgid "Submit" +msgstr "Soumettre" + +#: templates/registration/password_reset_complete.html:6 +msgid "Password reset successfully" +msgstr "Mot de passe réinitialisé" + +#: templates/registration/password_reset_confirm.html:17 +msgid "Password reset failed" +msgstr "La réinitialisation du mot de passe a échoué" + +#: templates/registration/password_reset_done.html:6 +msgid "Email with password reset instructions has been sent." +msgstr "" +"Un courriel avec les instructions pour la réinitialisation du mot de passe a " +"été envoyé." + +#: templates/registration/password_reset_email.html:2 +#, python-format +msgid "Reset password at %(site_name)s" +msgstr "Remise à réro du mot de passe pour %(site_name)s" + +#: templates/registration/password_reset_form.html:7 +msgid "Reset password" +msgstr "Réinitialisation du mot de passe" + +#: templates/registration/registration_complete.html:6 +msgid "You are now registered. Activation email sent." +msgstr "" +"Vous être maintenant enregistré. Un courriel d'activation de votre compte " +"vous a été envoyé." + +#~ msgid "References" +#~ msgstr "Référence" diff --git a/ishtar_common/management/__init__.py b/ishtar_common/management/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ishtar_common/management/__init__.py diff --git a/ishtar_common/management/commands/__init__.py b/ishtar_common/management/commands/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ishtar_common/management/commands/__init__.py diff --git a/ishtar_common/management/commands/generate_rights.py b/ishtar_common/management/commands/generate_rights.py new file mode 100644 index 000000000..75b1cf807 --- /dev/null +++ b/ishtar_common/management/commands/generate_rights.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +import sys + +from django.core.management.base import BaseCommand, CommandError +from django.core.exceptions import ObjectDoesNotExist + +import ishtar_base.forms_main as ishtar_forms +import ishtar_base.models as models + +class Command(BaseCommand): + args = '' + help = 'Regenerate rights for current forms' + + def handle(self, *args, **options): + wizards = [] + wizard_steps = {} + for attr in dir(ishtar_forms): + if not attr.endswith('_wizard'): + continue + wizard = getattr(ishtar_forms, attr) + url_name = wizard.url_name + try: + wizard_obj = models.Wizard.objects.get(url_name=url_name) + except ObjectDoesNotExist: + wizard_obj = models.Wizard.objects.create(url_name=url_name) + wizard_obj.save() + #self.stdout.write('* Wizard "%s" added\n' % url_name) + sys.stdout.write('* Wizard "%s" added\n' % url_name) + wizard_steps[url_name] = [] + for idx, step_url_name in enumerate(wizard.form_list.keys()): + form = wizard.form_list[step_url_name] + if issubclass(form, ishtar_forms.FinalForm): + break # don't reference the final form + step_values = {'name':unicode(form.form_label), + 'order':idx} + try: + step_obj = models.WizardStep.objects.get(wizard=wizard_obj, + url_name=step_url_name) + for k in step_values: + setattr(step_obj, k, step_values[k]) + step_obj.save() + except ObjectDoesNotExist: + step_values.update({'wizard':wizard_obj, + 'url_name':step_url_name}) + step_obj = models.WizardStep.objects.create(**step_values) + step_obj.save() + #self.stdout.write('* Wizard step "%s" added\n' \ + # % unicode(form.form_label)) + sys.stdout.write('* Wizard step "%s" added\n' \ + % unicode(form.form_label)) + wizard_steps[url_name].append(step_url_name) + #self.stdout.write('Successfully regeneration of wizard rights\n') + sys.stdout.write('Successfully regeneration of wizard rights\n') diff --git a/ishtar_common/menus.py b/ishtar_common/menus.py new file mode 100644 index 000000000..79355a6be --- /dev/null +++ b/ishtar_common/menus.py @@ -0,0 +1,331 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Menus +""" + +from django.utils.translation import ugettext_lazy as _ + +import models + +class SectionItem: + def __init__(self, idx, label, childs=[]): + self.idx = idx + self.label = label + self.childs = childs + self.available = False + self.items = {} + + def can_be_available(self, user): + for child in self.childs: + if child.can_be_available(user): + return True + return False + + def is_available(self, user, obj=None): + for child in self.childs: + if child.is_available(user, obj): + return True + return False + + def set_items(self, user, items): + if user: + self.available = self.can_be_available(user) + for child in self.childs: + child.set_items(user, items) + items[child.idx] = child + +class MenuItem: + def __init__(self, idx, label, model=None, access_controls=[]): + self.idx = idx + self.label = label + self.model = model + self.access_controls = access_controls + self.available = False + + def can_be_available(self, user): + if not self.access_controls: + return True + for access_control in self.access_controls: + access_control = self.model._meta.app_label + '.' + access_control + if user.has_perm(access_control, self.model): + return True + # manage by person type + if hasattr(user, 'ishtaruser'): + person_type = user.ishtaruser.person.person_type + if person_type.rights.filter(wizard__url_name=self.idx).count(): + return True + return False + + def is_available(self, user, obj=None): + if not self.access_controls: + return True + for access_control in self.access_controls: + access_control = self.model._meta.app_label + '.' + access_control + if user.has_perm(access_control, self.model, obj): + return True + # manage by person type + if hasattr(user, 'ishtaruser'): + person_type = user.ishtaruser.person.person_type + if person_type.rights.filter(wizard__url_name=self.idx).count(): + return True + return False + + def set_items(self, user, items): + if user: + self.available = self.can_be_available(user) + +class Menu: + def __init__(self, user): + self.user = user + self.initialized = False + self.childs = [ + SectionItem('administration', _(u"Administration"), + childs=[SectionItem('person', _(u"Person"), + childs=[ + MenuItem('person_creation', _(u"Creation"), + model=models.Person, + access_controls=['add_person', 'add_own_person']), + MenuItem('person_modification', _(u"Modification"), + model=models.Person, + access_controls=['change_person', 'change_own_person']), + ]), + MenuItem('account_management', _(u"Account management"), + model=models.IshtarUser, + access_controls=['add_ishtaruser',]), + ]), + SectionItem('file_management', _(u"Archaeological file"), + childs=[ + MenuItem('file_search', _(u"Search"), + model=models.File, + access_controls=['view_file', 'view_own_file']), + MenuItem('file_creation', _(u"Creation"), + model=models.File, + access_controls=['add_file', 'add_own_file']), + MenuItem('file_modification', _(u"Modification"), + model=models.File, + access_controls=['change_file', 'change_own_file']), + MenuItem('file_closing', _(u"Closing"), + model=models.File, + access_controls=['change_file', + 'change_own_file']), + MenuItem('file_deletion', _(u"Deletion"), + model=models.File, + access_controls=['delete_file', 'delete_own_file']), + SectionItem('admin_act_files', _(u"Administrative act"), + childs=[ + MenuItem('file_administrativeactfile', + _(u"Add"), + model=models.Operation, + access_controls=['change_file', 'change_own_file']), + MenuItem('file_administrativeactfile_modification', + _(u"Modification"), + model=models.AdministrativeAct, + access_controls=['change_file', 'change_own_file']), + MenuItem('file_administrativeactfile_deletion', + _(u"Deletion"), + model=models.AdministrativeAct, + access_controls=['delete_file', 'delete_own_file']), + ],), + ]), + SectionItem('operation_management', _(u"Operation"), + childs=[ + MenuItem('operation_search', _(u"Search"), + model=models.Operation, + access_controls=['view_operation', + 'view_own_operation']), + MenuItem('operation_creation', _(u"Creation"), + model=models.Operation, + access_controls=['add_operation', + 'add_own_operation']), + MenuItem('operation_modification', _(u"Modification"), + model=models.Operation, + access_controls=['change_operation', + 'change_own_operation']), + MenuItem('operation_closing', _(u"Closing"), + model=models.Operation, + access_controls=['change_operation', + 'change_own_operation']), + MenuItem('operation_deletion', _(u"Deletion"), + model=models.Operation, + access_controls=['change_operation', + 'change_own_operation']), + SectionItem('admin_act_operations', + _(u"Administrative act"), + childs=[ + MenuItem('operation_administrativeactop', + _(u"Add"), + model=models.Operation, + access_controls=['change_operation', + 'change_own_operation']), + MenuItem('operation_administrativeactop_modification', + _(u"Modification"), + model=models.AdministrativeAct, + access_controls=['change_operation', + 'change_own_operation']), + MenuItem('operation_administrativeactop_deletion', + _(u"Deletion"), + model=models.AdministrativeAct, + access_controls=['operation_deletion', + 'delete_own_operation']), + ],), + ]), + SectionItem('record_management', _(u"Context record"), + childs=[ + MenuItem('record_search', _(u"Search"), + model=models.ContextRecord, + access_controls=['view_contextrecord', + 'view_own_contextrecord']), + MenuItem('record_creation', _(u"Creation"), + model=models.ContextRecord, + access_controls=['add_contextrecord', + 'add_own_contextrecord']), + MenuItem('record_modification', _(u"Modification"), + model=models.ContextRecord, + access_controls=['change_contextrecord', + 'change_own_contextrecord']), + MenuItem('record_deletion', _(u"Deletion"), + model=models.ContextRecord, + access_controls=['delete_contextrecord', + 'delete_own_contextrecord']), + ]), + SectionItem('item_management', _(u"Item"), + childs=[ + MenuItem('item_search', _(u"Search"), + model=models.Item, + access_controls=['view_item', + 'view_own_item']), + MenuItem('item_creation', _(u"Creation"), + model=models.Item, + access_controls=['add_item', + 'add_own_item']), + MenuItem('item_modification', _(u"Modification"), + model=models.Item, + access_controls=['change_item', + 'change_own_item']), + MenuItem('warehouse_packaging', _(u"Packaging"), + model=models.Treatment, + access_controls=['add_treatment', 'add_own_treatment']), + #MenuItem('treatment_creation', _(u"Add a treatment"), + # model=models.Treatment, + # access_controls=['add_treatment', + # 'add_own_treatment']), + ]), + SectionItem('source_management', _(u"Documentation"), + childs=[ + SectionItem('admin_add_sources', _(u"Add"), + childs=[ + MenuItem('operation_source_creation', + _(u"Related to an operation"), + model=models.OperationSource, + access_controls=['change_operation', + 'change_own_operation']), + MenuItem('record_source_creation', + _(u"Related to a context record"), + model=models.ContextRecordSource, + access_controls=['change_contextrecord', + 'change_own_contextrecord']), + MenuItem('item_source_creation', + _(u"Related to an archaelogical item"), + model=models.ItemSource, + access_controls=['change_item', + 'change_own_item']), + ]), + SectionItem('admin_mod_sources', _(u"Modify"), + childs=[ + MenuItem('operation_source_modification', + _(u"Related to an operation"), + model=models.OperationSource, + access_controls=['change_operation', + 'change_own_operation']), + MenuItem('record_source_modification', + _(u"Related to a context record"), + model=models.ContextRecordSource, + access_controls=['change_contextrecord', + 'change_own_contextrecord']), + MenuItem('item_source_modification', + _(u"Related to an archaelogical item"), + model=models.ItemSource, + access_controls=['change_item', + 'change_own_item']), + ]), + SectionItem('admin_del_sources', _(u"Deletion"), + childs=[ + MenuItem('operation_source_deletion', + _(u"Related to an operation"), + model=models.OperationSource, + access_controls=['change_operation', + 'change_own_operation']), + MenuItem('record_source_deletion', + _(u"Related to a context record"), + model=models.ContextRecordSource, + access_controls=['change_contextrecord', + 'change_own_contextrecord']), + MenuItem('item_source_deletion', + _(u"Related to an archaelogical item"), + model=models.ItemSource, + access_controls=['change_item', + 'change_own_item']), + ]), + ]), + #SectionItem('warehouse', _(u"Warehouse"), + # childs=[ + # MenuItem('warehouse_inventory', _(u"Inventory"), + # model=models.Warehouse, + # access_controls=['change_warehouse',]), + # MenuItem('warehouse_recording', _(u"Recording"), + # model=models.Treatment, + # access_controls=['add_treatment', 'add_own_treatment']), + # MenuItem('warehouse_lend', _(u"Lending"), + # model=models.Treatment, + # access_controls=['add_treatment', 'add_own_treatment']), + # ]), + SectionItem('dashboard', _(u"Dashboard"), + childs=[ + MenuItem('dashboard_main', _(u"General informations"), + model=models.File, + access_controls=['change_file', 'change_own_file']), + MenuItem('dashboard_file', _(u"Archaeological files"), + model=models.File, + access_controls=['change_file', 'change_own_file']), + MenuItem('dashboard_operation', _(u"Operations"), + model=models.Operation, + access_controls=['change_operation', + 'change_own_operation']), + #MenuItem('dashboard_treatment', _(u"Treatments"), + # model=models.Treatment, + # access_controls=['change_treatment',]), + #MenuItem('dashboard_warehouse', _(u"Warehouses"), + # model=models.Warehouse, + # access_controls=['change_warehouse',]), + ]), + ] + self.items = {} + + def init(self): + if self.initialized: + return + self.items = {} + for main_menu in self.childs: + main_menu.set_items(self.user, self.items) + self.initialized = True + +menu = Menu(None) +menu.init() diff --git a/ishtar_common/models.py b/ishtar_common/models.py new file mode 100644 index 000000000..747643718 --- /dev/null +++ b/ishtar_common/models.py @@ -0,0 +1,2187 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Models description +""" +import datetime + +from django.conf import settings +from django.core.exceptions import ObjectDoesNotExist, ValidationError +from django.core.validators import validate_slug +from django.utils.translation import ugettext_lazy as _, ugettext +from django.utils.safestring import SafeUnicode, mark_safe +from django.core.urlresolvers import reverse, NoReverseMatch +from django.db.utils import DatabaseError +from django.db.models import Q, Max, Count, Sum, Avg +from django.db.models.signals import m2m_changed, post_save + +from django.contrib.auth.models import User +from django.contrib.gis.db import models +from django.contrib import admin + +from simple_history.models import HistoricalRecords as BaseHistoricalRecords + +JOINT = u" - " + +def post_save_user(sender, **kwargs): + if not kwargs['created']: + return + user = kwargs['instance'] + if not IshtarUser.objects.filter(username=user.username).count(): + IshtarUser.create_from_user(user) +post_save.connect(post_save_user, sender=User) + +# HistoricalRecords enhancement: don't save identical versions +class HistoricalRecords(BaseHistoricalRecords): + def create_historical_record(self, instance, type): + manager = getattr(instance, self.manager_name) + attrs = {} + for field in instance._meta.fields: + attrs[field.attname] = getattr(instance, field.attname) + history = instance.history.all() + if not history: + manager.create(history_type=type, **attrs) + return + old_instance = history[0] + for field in instance._meta.fields: + if getattr(old_instance, field.attname) != attrs[field.attname]: + manager.create(history_type=type, **attrs) + return + +# valid ID validator for models +def valid_id(cls): + def func(value): + try: + cls.objects.get(pk=value) + except ObjectDoesNotExist: + raise ValidationError(_(u"Not a valid item.")) + return func + +def valid_ids(cls): + def func(value): + if "," in value: + value = value.split(",") + for v in value: + try: + cls.objects.get(pk=v) + except ObjectDoesNotExist: + raise ValidationError( + _(u"An item selected is not a valid item.")) + return func + +# unique validator for models +def is_unique(cls, field): + def func(value): + query = {field:value} + try: + assert cls.objects.filter(**query).count() == 0 + except AssertionError: + raise ValidationError(_(u"This item already exist.")) + return func + +class OwnPerms: + """ + Manage special permissions for object's owner + """ + @classmethod + def get_query_owns(cls, user): + """ + Query object to get own items + """ + return None # implement for each object + + def is_own(self, user): + """ + Check if the current object is owned by the user + """ + query = self.get_query_owns(user) + if not query: + return False + query = query & Q(pk=self.pk) + return cls.objects.filter(query).count() + + @classmethod + def has_item_of(cls, user): + """ + Check if the user own some items + """ + query = cls.get_query_owns(user) + if not query: + return False + return cls.objects.filter(query).count() + + @classmethod + def get_owns(cls, user): + """ + Get Own items + """ + if isinstance(user, User): + user = IshtarUser.objects.get(user_ptr=user) + if user.is_anonymous(): + return [] + query = cls.get_query_owns(user) + if not query: + return [] + return cls.objects.filter(query).order_by(*cls._meta.ordering).all() + +class GeneralType(models.Model): + """ + Abstract class for "types" + """ + label = models.CharField(_(u"Label"), max_length=100) + txt_idx = models.CharField(_(u"Textual ID"), + validators=[validate_slug], max_length=30, unique=True) + comment = models.TextField(_(u"Comment"), blank=True, null=True) + available = models.BooleanField(_(u"Available")) + HELP_TEXT = u"" + + class Meta: + abstract = True + + def __unicode__(self): + return self.label + + @classmethod + def get_help(cls, dct={}, exclude=[]): + help_text = cls.HELP_TEXT + c_rank = -1 + help_items = u"\n" + for item in cls.get_types(dct=dct, instances=True, exclude=exclude): + if hasattr(item, '__iter__'): + # TODO: manage multiple levels + continue + if not item.comment: + continue + if c_rank > item.rank: + help_items += u"</dl>\n" + elif c_rank < item.rank: + help_items += u"<dl>\n" + c_rank = item.rank + help_items += u"<dt>%s</dt><dd>%s</dd>" % (item.label, + u"<br/>".join(item.comment.split('\n'))) + c_rank += 1 + if c_rank: + help_items += c_rank*u"</dl>" + if help_text or help_items != u'\n': + return mark_safe(help_text + help_items) + return u"" + + @classmethod + def get_types(cls, dct={}, instances=False, exclude=[]): + base_dct = dct.copy() + if hasattr(cls, 'parent'): + return cls._get_parent_types(base_dct, instances, exclude=exclude) + return cls._get_types(base_dct, instances, exclude=exclude) + + @classmethod + def _get_types(cls, dct={}, instances=False, exclude=[]): + dct['available'] = True + if not instances: + yield ('', '--') + items = cls.objects.filter(**dct) + if exclude: + items = items.exclude(txt_idx__in=exclude) + for item in items.all(): + if instances: + item.rank = 0 + yield item + else: + yield (item.pk, _(unicode(item))) + + PREFIX = "› " + + @classmethod + def _get_childs(cls, item, dct, prefix=0, instances=False, exclude=[]): + prefix += 1 + dct['parent'] = item + childs = cls.objects.filter(**dct) + if exclude: + childs = childs.exclude(txt_idx__in=exclude) + if hasattr(cls, 'order'): + childs = childs.order_by('order') + for child in childs.all(): + if instances: + child.rank = prefix + yield child + else: + yield (child.pk, SafeUnicode(prefix*cls.PREFIX + \ + unicode(_(unicode(child))) )) + for sub_child in cls._get_childs(child, dct, prefix, instances, + exclude=exclude): + yield sub_child + + @classmethod + def _get_parent_types(cls, dct={}, instances=False, exclude=[]): + dct['available'] = True + if not instances: + yield ('', '--') + dct['parent'] = None + items = cls.objects.filter(**dct) + if exclude: + items = items.exclude(txt_idx__in=exclude) + if hasattr(cls, 'order'): + items = items.order_by('order') + for item in items.all(): + if instances: + item.rank = 0 + yield item + else: + yield (item.pk, unicode(item)) + for child in cls._get_childs(item, dct, instances, exclude=exclude): + yield child + +class HistoryError(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) + +class BaseHistorizedItem(models.Model): + history_modifier = models.ForeignKey(User, related_name='+', + verbose_name=_(u"Last editor")) + class Meta: + abstract = True + + def save(self, *args, **kwargs): + assert hasattr(self, 'history_modifier') == True + super(BaseHistorizedItem, self).save(*args, **kwargs) + return True + + def get_previous(self, step=None, date=None, strict=True): + """ + Get a "step" previous state of the item + """ + assert step or date + historized = self.history.all() + item = None + if step: + assert len(historized) > step + item = historized[step] + else: + for step, item in enumerate(historized): + if item.history_date == date: + break + # ended with no match + if item.history_date != date: + return + item._step = step + if len(historized) != (step + 1): + item._previous = historized[step + 1].history_date + else: + item._previous = None + if step > 0: + item._next = historized[step - 1].history_date + else: + item._next = None + item.history_date = historized[step].history_date + model = self.__class__ + for k in model._meta.get_all_field_names(): + field = model._meta.get_field_by_name(k)[0] + if hasattr(field, 'rel') and field.rel: + if not hasattr(item, k+'_id'): + setattr(item, k, getattr(self, k)) + continue + val = getattr(item, k+'_id') + if not val: + setattr(item, k, None) + continue + try: + val = field.rel.to.objects.get(pk=val) + setattr(item, k, val) + except ObjectDoesNotExist: + if strict: + raise HistoryError(u"The class %s has no pk %d" % ( + unicode(field.rel.to), val)) + setattr(item, k, None) + item.pk = self.pk + return item + + def rollback(self, date): + """ + Rollback to a previous state + """ + to_del, new_item = [], None + for item in self.history.all(): + to_del.append(item) + if item.history_date == date: + new_item = item + break + if not new_item: + raise HistoryError(u"The date to rollback to doesn't exist.") + try: + for f in self._meta.fields: + k = f.name + if k != 'id' and hasattr(self, k): + if not hasattr(new_item, k): + k = k + "_id" + setattr(self, k, getattr(new_item, k)) + self.save() + except: + raise HistoryError(u"The rollback has failed.") + # clean the obsolete history + for historized_item in to_del: + historized_item.delete() + + def values(self): + values = {} + for f in self._meta.fields: + k = f.name + if k != 'id': + values[k] = getattr(self, k) + return values + + def get_show_url(self): + try: + return reverse('show-'+self.__class__.__name__.lower(), + args=[self.pk, '']) + except NoReverseMatch: + return + +class LightHistorizedItem(BaseHistorizedItem): + history_date = models.DateTimeField(default=datetime.datetime.now) + class Meta: + abstract = True + + def save(self, *args, **kwargs): + super(LightHistorizedItem, self).save(*args, **kwargs) + return True + +class Wizard(models.Model): + url_name = models.CharField(_(u"URL name"), max_length=128, unique=True) + class Meta: + verbose_name = _(u"Wizard") + ordering = ['url_name'] + + def __unicode__(self): + return unicode(self.url_name) + +class WizardStep(models.Model): + order = models.IntegerField(_(u"Order")) + wizard = models.ForeignKey(Wizard, verbose_name=_(u"Wizard")) + url_name = models.CharField(_(u"URL name"), max_length=128) + name = models.CharField(_(u"Label"), max_length=128) + class Meta: + verbose_name = _(u"Wizard step") + ordering = ['wizard', 'order'] + + def __unicode__(self): + return u"%s » %s" % (unicode(self.wizard), unicode(self.name)) + +class UserDashboard: + def __init__(self): + types = IshtarUser.objects.values('person__person_type', + 'person__person_type__label') + self.types = types.annotate(number=Count('pk'))\ + .order_by('person__person_type') + +class FileDashboard: + def __init__(self): + main_dashboard = Dashboard(File) + + self.total_number = main_dashboard.total_number + + types = File.objects.values('file_type', 'file_type__label') + self.types = types.annotate(number=Count('pk')).order_by('file_type') + + by_year = File.objects.extra( + {'date':"date_trunc('year', creation_date)"}) + self.by_year = by_year.values('date')\ + .annotate(number=Count('pk')).order_by('-date') + + now = datetime.date.today() + limit = datetime.date(now.year, now.month, 1) - datetime.timedelta(365) + by_month = File.objects.filter(creation_date__gt=limit).extra( + {'date':"date_trunc('month', creation_date)"}) + self.by_month = by_month.values('date')\ + .annotate(number=Count('pk')).order_by('-date') + + # research + self.research = {} + prog_type = FileType.objects.get(txt_idx='prog') + researchs = File.objects.filter(file_type=prog_type) + self.research['total_number'] = researchs.count() + by_year = researchs.extra({'date':"date_trunc('year', creation_date)"}) + self.research['by_year'] = by_year.values('date')\ + .annotate(number=Count('pk'))\ + .order_by('-date') + by_month = researchs.filter(creation_date__gt=limit)\ + .extra({'date':"date_trunc('month', creation_date)"}) + self.research['by_month'] = by_month.values('date')\ + .annotate(number=Count('pk'))\ + .order_by('-date') + + self.research['by_dpt'] = FileByDepartment.objects\ + .filter(file__file_type=prog_type, + department__isnull=False)\ + .values('department__label')\ + .annotate(number=Count('file'))\ + .order_by('department__label') + FileTown = File.towns.through + self.research['towns'] = FileTown.objects\ + .filter(file__file_type=prog_type)\ + .values('town__name')\ + .annotate(number=Count('file'))\ + .order_by('-number','town__name')[:10] + + # rescue + rescue_type = FileType.objects.get(txt_idx='preventive') + rescues = File.objects.filter(file_type=rescue_type) + self.rescue = {} + self.rescue['total_number'] = rescues.count() + self.rescue['saisine'] = rescues.values('saisine_type__label')\ + .annotate(number=Count('pk'))\ + .order_by('saisine_type__label') + self.rescue['administrative_act'] = AdministrativeAct.objects\ + .filter(associated_file__isnull=False)\ + .values('act_type__label')\ + .annotate(number=Count('pk'))\ + .order_by('act_type__pk') + + by_year = rescues.extra({'date':"date_trunc('year', creation_date)"}) + self.rescue['by_year'] = by_year.values('date')\ + .annotate(number=Count('pk'))\ + .order_by('-date') + by_month = rescues.filter(creation_date__gt=limit)\ + .extra({'date':"date_trunc('month', creation_date)"}) + self.rescue['by_month'] = by_month.values('date')\ + .annotate(number=Count('pk'))\ + .order_by('-date') + + self.rescue['by_dpt'] = FileByDepartment.objects\ + .filter(file__file_type=rescue_type, + department__isnull=False)\ + .values('department__label')\ + .annotate(number=Count('file'))\ + .order_by('department__label') + self.rescue['towns'] = FileTown.objects\ + .filter(file__file_type=rescue_type)\ + .values('town__name')\ + .annotate(number=Count('file'))\ + .order_by('-number','town__name')[:10] + + self.rescue['with_associated_operation'] = rescues\ + .filter(operations__isnull=False).count() + + self.rescue['with_associated_operation_percent'] = round( + float(self.rescue['with_associated_operation'])\ + /self.rescue['total_number']*100, 2) + + by_year_operationnal = rescues.filter(operations__isnull=False)\ + .extra({'date':"date_trunc('year', creation_date)"}) + by_year_operationnal = by_year_operationnal.values('date')\ + .annotate(number=Count('pk'))\ + .order_by('-date') + percents, idx = [], 0 + for dct in self.rescue['by_year']: + if idx > len(by_year_operationnal): + break + if by_year_operationnal[idx]['date'] != dct['date'] or\ + not dct['number']: + continue + val = round(float(by_year_operationnal[idx]['number'])/\ + dct['number']*100, 2) + percents.append({'date':dct['date'], 'number':val}) + self.rescue['operational_by_year'] = percents + + self.rescue['surface_by_town'] = FileTown.objects\ + .filter(file__file_type=rescue_type)\ + .values('town__name')\ + .annotate(number=Sum('file__total_surface'))\ + .order_by('-number','town__name')[:10] + self.rescue['surface_by_dpt'] = FileByDepartment.objects\ + .filter(file__file_type=rescue_type, + department__isnull=False)\ + .values('department__label')\ + .annotate(number=Sum('file__total_surface'))\ + .order_by('department__label') + +class OperationDashboard: + def __init__(self): + main_dashboard = Dashboard(Operation) + + self.total_number = main_dashboard.total_number + + self.filters_keys = ['recorded', 'effective', 'active', 'field', + 'documented', 'closed', 'documented_closed'] + filters = { + 'recorded':{}, + 'effective':{'in_charge__isnull':False}, + 'active':{'in_charge__isnull':False, 'end_date__isnull':True}, + 'field':{'excavation_end_date__isnull':True}, + 'documented':{'source__isnull':False}, + 'documented_closed':{'source__isnull':False, + 'end_date__isnull':False}, + 'closed':{'end_date__isnull':False} + } + filters_label = { + 'recorded':_(u"Recorded"), + 'effective':_(u"Effective"), + 'active':_(u"Active"), + 'field':_(u"Field completed"), + 'documented':_(u"Associated report"), + 'closed':_(u"Closed"), + 'documented_closed':_(u"Documented and closed"), + } + self.filters_label = [filters_label[k] for k in self.filters_keys] + self.total = [] + for fltr_key in self.filters_keys: + fltr, lbl = filters[fltr_key], filters_label[fltr_key] + nb = Operation.objects.filter(**fltr).count() + self.total.append((lbl, nb)) + + self.surface_by_type = Operation.objects\ + .values('operation_type__label')\ + .annotate(number=Sum('surface'))\ + .order_by('-number','operation_type__label') + + self.by_type = [] + self.types = OperationType.objects.filter(available=True).all() + for fltr_key in self.filters_keys: + fltr, lbl = filters[fltr_key], filters_label[fltr_key] + type_res = Operation.objects.filter(**fltr).\ + values('operation_type', 'operation_type__label').\ + annotate(number=Count('pk')).\ + order_by('operation_type') + types_dct = {} + for typ in type_res.all(): + types_dct[typ['operation_type']] = typ["number"] + types = [] + for typ in self.types: + if typ.pk in types_dct: + types.append(types_dct[typ.pk]) + else: + types.append(0) + self.by_type.append((lbl, types)) + + self.by_year = [] + self.years = [res['year'] for res in Operation.objects.values('year')\ + .order_by('-year').distinct()] + for fltr_key in self.filters_keys: + fltr, lbl = filters[fltr_key], filters_label[fltr_key] + year_res = Operation.objects.filter(**fltr).\ + values('year').\ + annotate(number=Count('pk')).\ + order_by('year') + years_dct = {} + for yr in year_res.all(): + years_dct[yr['year']] = yr["number"] + years = [] + for yr in self.years: + if yr in years_dct: + years.append(years_dct[yr]) + else: + years.append(0) + self.by_year.append((lbl, years)) + + self.by_realisation_year = [] + self.realisation_years = [res['date'] for res in \ + Operation.objects.extra( + {'date':"date_trunc('year', start_date)"}).values('date')\ + .filter(start_date__isnull=False).order_by('-date').distinct()] + for fltr_key in self.filters_keys: + fltr, lbl = filters[fltr_key], filters_label[fltr_key] + year_res = Operation.objects.filter(**fltr).extra( + {'date':"date_trunc('year', start_date)"}).values('date').\ + values('date').filter(start_date__isnull=False).\ + annotate(number=Count('pk')).\ + order_by('-date') + years_dct = {} + for yr in year_res.all(): + years_dct[yr['date']] = yr["number"] + years = [] + for yr in self.realisation_years: + if yr in years_dct: + years.append(years_dct[yr]) + else: + years.append(0) + self.by_realisation_year.append((lbl, years)) + + self.effective = [] + for typ in self.types: + year_res = Operation.objects.filter(**{'in_charge__isnull':False, + 'operation_type':typ}).\ + values('year').\ + annotate(number=Count('pk')).\ + order_by('-year').distinct() + years_dct = {} + for yr in year_res.all(): + years_dct[yr['year']] = yr["number"] + years = [] + for yr in self.years: + if yr in years_dct: + years.append(years_dct[yr]) + else: + years.append(0) + self.effective.append((typ, years)) + + # TODO: by date + now = datetime.date.today() + limit = datetime.date(now.year, now.month, 1) - datetime.timedelta(365) + by_realisation_month = Operation.objects.filter(start_date__gt=limit, + start_date__isnull=False).extra( + {'date':"date_trunc('month', start_date)"}) + self.last_months = [] + date = datetime.datetime(now.year, now.month, 1) + for mt_idx in xrange(12): + self.last_months.append(date) + if date.month > 1: + date = datetime.datetime(date.year, date.month - 1, 1) + else: + date = datetime.datetime(date.year - 1, 12, 1) + self.by_realisation_month = [] + for fltr_key in self.filters_keys: + fltr, lbl = filters[fltr_key], filters_label[fltr_key] + month_res = by_realisation_month.filter(**fltr).\ + annotate(number=Count('pk')).\ + order_by('-date') + month_dct = {} + for mt in month_res.all(): + month_dct[mt.date] = mt.number + date = datetime.date(now.year, now.month, 1) + months = [] + for date in self.last_months: + if date in month_dct: + months.append(month_dct[date]) + else: + months.append(0) + self.by_realisation_month.append((lbl, months)) + + # survey and excavations + self.survey, self.excavation = {}, {} + for dct_res, ope_types in ((self.survey, ('arch_diagnostic',)), + (self.excavation, ('prev_excavation', + 'prog_excavation'))): + dct_res['total'] = [] + operation_type = {'operation_type__txt_idx__in':ope_types} + for fltr_key in self.filters_keys: + fltr, lbl = filters[fltr_key], filters_label[fltr_key] + fltr.update(operation_type) + nb = Operation.objects.filter(**fltr).count() + dct_res['total'].append((lbl, nb)) + + dct_res['by_year'] = [] + for fltr_key in self.filters_keys: + fltr, lbl = filters[fltr_key], filters_label[fltr_key] + fltr.update(operation_type) + year_res = Operation.objects.filter(**fltr).\ + values('year').\ + annotate(number=Count('pk')).\ + order_by('year') + years_dct = {} + for yr in year_res.all(): + years_dct[yr['year']] = yr["number"] + years = [] + for yr in self.years: + if yr in years_dct: + years.append(years_dct[yr]) + else: + years.append(0) + dct_res['by_year'].append((lbl, years)) + + dct_res['by_realisation_year'] = [] + for fltr_key in self.filters_keys: + fltr, lbl = filters[fltr_key], filters_label[fltr_key] + fltr.update(operation_type) + year_res = Operation.objects.filter(**fltr).extra( + {'date':"date_trunc('year', start_date)"}).values('date').\ + filter(start_date__isnull=False).\ + annotate(number=Count('pk')).\ + order_by('-date') + years_dct = {} + for yr in year_res.all(): + years_dct[yr['date']] = yr["number"] + years = [] + for yr in self.realisation_years: + if yr in years_dct: + years.append(years_dct[yr]) + else: + years.append(0) + dct_res['by_realisation_year'].append((lbl, years)) + + current_year_ope = Operation.objects.filter(**operation_type)\ + .filter(year=datetime.date.today().year) + current_realisation_year_ope = Operation.objects\ + .filter(**operation_type)\ + .filter(start_date__year=datetime.date.today().year) + res_keys = [('area_realised', current_realisation_year_ope)] + if dct_res == self.survey: + res_keys.append(('area', + current_year_ope)) + for res_key, base_ope in res_keys: + dct_res[res_key] = [] + for fltr_key in self.filters_keys: + fltr, lbl = filters[fltr_key], filters_label[fltr_key] + area_res = base_ope.filter(**fltr)\ + .annotate(number=Sum('surface')).all() + val = 0 + if area_res: + val = area_res[0].number + dct_res[res_key].append(val) + # TODO... + res_keys = [('manday_realised', current_realisation_year_ope)] + if dct_res == self.survey: + res_keys.append(('manday', + current_year_ope)) + for res_key, base_ope in res_keys: + dct_res[res_key] = [] + for fltr_key in self.filters_keys: + dct_res[res_key].append('-') + # TODO... + res_keys = [('mandayhect_realised', current_realisation_year_ope)] + if dct_res == self.survey: + res_keys.append(('mandayhect', + current_year_ope)) + for res_key, base_ope in res_keys: + dct_res[res_key] = [] + for fltr_key in self.filters_keys: + dct_res[res_key].append('-') + # TODO... + dct_res['mandayhect_real_effective'] = '-' + if dct_res == self.survey: + dct_res['mandayhect_effective'] = '-' + + + res_keys = [('org_realised', current_realisation_year_ope)] + if dct_res == self.survey: + res_keys.append(('org', current_year_ope)) + for res_key, base_ope in res_keys: + org_res = base_ope.filter(in_charge__attached_to__isnull=False)\ + .values('in_charge__attached_to', + 'in_charge__attached_to__name')\ + .annotate(area=Sum('surface'))\ + .order_by('in_charge__attached_to__name').all() + # TODO: man-days, man-days/hectare + dct_res[res_key] = org_res + + + year_ope = Operation.objects.filter(**operation_type) + res_keys = ['org_by_year'] + if dct_res == self.survey: + res_keys.append('org_by_year_realised') + q = year_ope.values('in_charge__attached_to', + 'in_charge__attached_to__name').\ + filter(in_charge__attached_to__isnull=False).\ + order_by('in_charge__attached_to__name').distinct() + org_list = [(org['in_charge__attached_to'], + org['in_charge__attached_to__name']) for org in q] + org_list_dct = dict(org_list) + for res_key in res_keys: + dct_res[res_key] = [] + years = self.years + if res_key == 'org_by_year_realised': + years = self.realisation_years + for org_id, org_label in org_list: + org_res = year_ope.filter(in_charge__attached_to__pk=org_id) + key_date = '' + if res_key == 'org_by_year': + org_res = org_res.values('year') + key_date = 'year' + else: + org_res = org_res.extra( + {'date':"date_trunc('year', start_date)"}).values('date').\ + filter(start_date__isnull=False) + key_date = 'date' + org_res = org_res.annotate(area=Sum('surface'), + cost=Sum('cost')) + years_dct = {} + for yr in org_res.all(): + area = yr['area'] if yr['area'] else 0 + cost = yr['cost'] if yr['cost'] else 0 + years_dct[yr[key_date]] = (area, cost) + r_years = [] + for yr in years: + if yr in years_dct: + r_years.append(years_dct[yr]) + else: + r_years.append((0, 0)) + dct_res[res_key].append((org_label, r_years)) + area_means, area_sums = [], [] + cost_means, cost_sums = [], [] + for idx, year in enumerate(years): + vals = [r_years[idx] for lbl, r_years in dct_res[res_key]] + sum_area = sum([a for a, c in vals]) + sum_cost = sum([c for a, c in vals]) + area_means.append(sum_area/len(vals)) + area_sums.append(sum_area) + cost_means.append(sum_cost/len(vals)) + cost_sums.append(sum_cost) + dct_res[res_key+'_area_mean'] = area_means + dct_res[res_key+'_area_sum'] = area_sums + dct_res[res_key+'_cost_mean'] = cost_means + dct_res[res_key+'_cost_mean'] = cost_sums + + if dct_res == self.survey: + self.survey['effective'] = [] + for yr in self.years: + year_res = Operation.objects.filter(in_charge__isnull=False, + year=yr).\ + annotate(number=Sum('surface'), + mean=Avg('surface')) + nb = year_res[0].number if year_res.count() else 0 + nb = nb if nb else 0 + mean = year_res[0].mean if year_res.count() else 0 + mean = mean if mean else 0 + self.survey['effective'].append((nb, mean)) + + # TODO:Man-Days/hectare by Year + + # CHECK: month of realisation or month? + dct_res['by_month'] = [] + for fltr_key in self.filters_keys: + fltr, lbl = filters[fltr_key], filters_label[fltr_key] + fltr.update(operation_type) + month_res = by_realisation_month.filter(**fltr).\ + annotate(number=Count('pk')).\ + order_by('-date') + month_dct = {} + for mt in month_res.all(): + month_dct[mt.date] = mt.number + date = datetime.date(now.year, now.month, 1) + months = [] + for date in self.last_months: + if date in month_dct: + months.append(month_dct[date]) + else: + months.append(0) + dct_res['by_month'].append((lbl, months)) + + operation_type = {'operation_type__txt_idx__in':ope_types} + self.departments = [(fd['department__pk'], fd['department__label']) + for fd in OperationByDepartment.objects\ + .filter(department__isnull=False)\ + .values('department__label', 'department__pk')\ + .order_by('department__label').distinct()] + dct_res['by_dpt'] = [] + for dpt_id, dpt_label in self.departments: + vals = OperationByDepartment.objects\ + .filter(department__pk=dpt_id, + operation__operation_type__txt_idx__in=ope_types)\ + .values('department__pk', 'operation__year')\ + .annotate(number=Count('operation'))\ + .order_by('operation__year') + dct_years = {} + for v in vals: + dct_years[v['operation__year']] = v['number'] + years = [] + for y in self.years: + if y in dct_years: + years.append(dct_years[y]) + else: + years.append(0) + years.append(sum(years)) + dct_res['by_dpt'].append((dpt_label, years)) + dct_res['effective_by_dpt'] = [] + for dpt_id, dpt_label in self.departments: + vals = OperationByDepartment.objects\ + .filter(department__pk=dpt_id, + operation__in_charge__isnull=False, + operation__operation_type__txt_idx__in=ope_types)\ + .values('department__pk', 'operation__year')\ + .annotate(number=Count('operation'), + area=Sum('operation__surface'), + fnap=Sum('operation__fnap_cost'), + cost=Sum('operation__cost'))\ + .order_by('operation__year') + dct_years = {} + for v in vals: + values = [] + for value in (v['number'], v['area'], v['cost'], v['fnap']): + values.append(value if value else 0) + dct_years[v['operation__year']] = values + years = [] + for y in self.years: + if y in dct_years: + years.append(dct_years[y]) + else: + years.append((0, 0, 0, 0)) + nbs, areas, costs, fnaps = zip(*years) + years.append((sum(nbs), sum(areas), sum(costs), sum(fnaps))) + dct_res['effective_by_dpt'].append((dpt_label, years)) + + OperationTown = Operation.towns.through + query = OperationTown.objects\ + .filter(operation__in_charge__isnull=False, + operation__operation_type__txt_idx__in=ope_types)\ + .values('town__name', 'town__departement__number')\ + .annotate(nb=Count('operation'))\ + .order_by('-nb', 'town__name')[:10] + dct_res['towns'] = [] + for r in query: + dct_res['towns'].append((u"%s (%s)" % (r['town__name'], + r['town__departement__number']), + r['nb'])) + + if dct_res == self.survey: + query = OperationTown.objects\ + .filter(operation__in_charge__isnull=False, + operation__operation_type__txt_idx__in=ope_types, + operation__surface__isnull=False)\ + .values('town__name', 'town__departement__number')\ + .annotate(nb=Sum('operation__surface'))\ + .order_by('-nb', 'town__name')[:10] + dct_res['towns_surface'] = [] + for r in query: + dct_res['towns_surface'].append((u"%s (%s)" % ( + r['town__name'], r['town__departement__number']), + r['nb'])) + else: + query = OperationTown.objects\ + .filter(operation__in_charge__isnull=False, + operation__operation_type__txt_idx__in=ope_types, + operation__cost__isnull=False)\ + .values('town__name', 'town__departement__number')\ + .annotate(nb=Sum('operation__cost'))\ + .order_by('-nb', 'town__name')[:10] + dct_res['towns_cost'] = [] + for r in query: + dct_res['towns_cost'].append((u"%s (%s)" % (r['town__name'], + r['town__departement__number']), + r['nb'])) + +class Dashboard: + def __init__(self, model): + self.model = model + self.total_number = model.get_total_number() + history_model = self.model.history.model + # last edited - created + self.recents, self.lasts = [], [] + for last_lst, modif_type in ((self.lasts, '+'), (self.recents, '~')): + last_ids = history_model.objects.values('id')\ + .annotate(hd=Max('history_date')) + last_ids = last_ids.filter(history_type=modif_type) + if self.model == Item: + last_ids = last_ids.filter(downstream_treatment_id__isnull=True) + if modif_type == '+': + last_ids = last_ids.filter(upstream_treatment_id__isnull=True) + last_ids = last_ids.order_by('-hd').distinct().all()[:5] + for idx in last_ids: + try: + obj = self.model.objects.get(pk=idx['id']) + except: + # deleted object are always referenced in history + continue + obj.history_date = idx['hd'] + last_lst.append(obj) + # years + self.years = model.get_years() + self.years.sort() + if not self.total_number or not self.years: + return + self.values = [('year', _(u"Year"), reversed(self.years))] + # numbers + self.numbers = [model.get_by_year(year).count() for year in self.years] + self.values += [('number', _(u"Number"), reversed(self.numbers))] + # calculate + self.average = self.get_average() + self.variance = self.get_variance() + self.standard_deviation = self.get_standard_deviation() + self.median = self.get_median() + self.mode = self.get_mode() + # by operation + if not hasattr(model, 'get_by_operation'): + return + operations = model.get_operations() + operation_numbers = [model.get_by_operation(op).count() + for op in operations] + # calculate + self.operation_average = self.get_average(operation_numbers) + self.operation_variance = self.get_variance(operation_numbers) + self.operation_standard_deviation = self.get_standard_deviation( + operation_numbers) + self.operation_median = self.get_median(operation_numbers) + operation_mode_pk = self.get_mode(dict(zip(operations, + operation_numbers))) + if operation_mode_pk: + self.operation_mode = unicode(Operation.objects.get( + pk=operation_mode_pk)) + + def get_average(self, vals=[]): + if not vals: + vals = self.numbers + return sum(vals)/len(vals) + + def get_variance(self, vals=[]): + if not vals: + vals = self.numbers + avrg = self.get_average(vals) + return self.get_average([(x-avrg)**2 for x in vals]) + + def get_standard_deviation(self, vals=[]): + if not vals: + vals = self.numbers + return round(self.get_variance(vals)**0.5, 3) + + def get_median(self, vals=[]): + if not vals: + vals = self.numbers + len_vals = len(vals) + vals.sort() + if (len_vals % 2) == 1: + return vals[len_vals/2] + else: + return (vals[len_vals/2-1] + vals[len_vals/2])/2.0 + + def get_mode(self, vals={}): + if not vals: + vals = dict(zip(self.years, self.numbers)) + mx = max(vals.values()) + for v in vals: + if vals[v] == mx: + return v + +class Departement(models.Model): + label = models.CharField(_(u"Label"), max_length=30) + number = models.CharField(_(u"Number"), unique=True, max_length=3) + + class Meta: + verbose_name = _(u"Departement") + verbose_name_plural = _(u"Departements") + ordering = ['number'] + + def __unicode__(self): + return unicode(self.number) + JOINT + self.label + +class Address(BaseHistorizedItem): + address = models.TextField(_(u"Address"), null=True, blank=True) + address_complement = models.TextField(_(u"Address complement"), null=True, + blank=True) + postal_code = models.CharField(_(u"Postal code"), max_length=10, null=True, + blank=True) + town = models.CharField(_(u"Town"), max_length=30, null=True, blank=True) + country = models.CharField(_(u"Country"), max_length=30, null=True, + blank=True) + phone = models.CharField(_(u"Phone"), max_length=18, null=True, blank=True) + mobile_phone = models.CharField(_(u"Mobile phone"), max_length=18, + null=True, blank=True) + history = HistoricalRecords() + + class Meta: + abstract = True + +class OrganizationType(GeneralType): + class Meta: + verbose_name = _(u"Organization type") + verbose_name_plural = _(u"Organization types") + +class Organization(Address, OwnPerms): + name = models.CharField(_(u"Name"), max_length=100) + organization_type = models.ForeignKey(OrganizationType, + verbose_name=_(u"Type")) + history = HistoricalRecords() + class Meta: + verbose_name = _(u"Organization") + verbose_name_plural = _(u"Organizations") + permissions = ( + ("view_own_organization", ugettext(u"Can view own Organization")), + ("add_own_organization", ugettext(u"Can add own Organization")), + ("change_own_organization", ugettext(u"Can change own Organization")), + ("delete_own_organization", ugettext(u"Can delete own Organization")), + ) + + def __unicode__(self): + return self.name + +class PersonType(GeneralType): + rights = models.ManyToManyField(WizardStep, verbose_name=_(u"Rights")) + class Meta: + verbose_name = _(u"Person type") + verbose_name_plural = _(u"Person types") + +class Person(Address, OwnPerms) : + TYPE = (('Mr', _(u'Mr')), + ('Ms', _(u'Miss')), + ('Md', _(u'Mrs')), + ('Dr', _(u'Doctor')), + ) + title = models.CharField(_(u"Title"), max_length=2, choices=TYPE) + surname = models.CharField(_(u"Surname"), max_length=20) + name = models.CharField(_(u"Name"), max_length=30) + email = models.CharField(_(u"Email"), max_length=40, blank=True, null=True) + person_type = models.ForeignKey(PersonType, verbose_name=_(u"Type")) + attached_to = models.ForeignKey('Organization', + verbose_name=_(u"Is attached to"), blank=True, null=True) + + class Meta: + verbose_name = _(u"Person") + verbose_name_plural = _(u"Persons") + permissions = ( + ("view_person", ugettext(u"Can view Person")), + ("view_own_person", ugettext(u"Can view own Person")), + ("add_own_person", ugettext(u"Can add own Person")), + ("change_own_person", ugettext(u"Can change own Person")), + ("delete_own_person", ugettext(u"Can delete own Person")), + ) + + def __unicode__(self): + lbl = u"%s %s" % (self.name, self.surname) + lbl += JOINT + if self.attached_to: + lbl += unicode(self.attached_to) + elif self.email: + lbl += self.email + return lbl + + def full_label(self): + return u" ".join([unicode(getattr(self, attr)) + for attr in ('title', 'surname', 'name', 'attached_to') + if getattr(self, attr)]) + +class IshtarUser(User): + person = models.ForeignKey(Person, verbose_name=_(u"Person"), unique=True) + + class Meta: + verbose_name = _(u"Ishtar user") + verbose_name_plural = _(u"Ishtar users") + + @classmethod + def create_from_user(cls, user): + default = user.username + surname = user.first_name or default + name = user.last_name or default + email = user.email + person_type = None + if user.is_superuser: + person_type = PersonType.objects.get(txt_idx='administrator') + else: + person_type = PersonType.objects.get(txt_idx='public_access') + person = Person.objects.create(title='Mr', surname=surname, + name=name, email=email, + person_type=person_type, + history_modifier=user) + return IshtarUser.objects.create(user_ptr=user, person=person) + +class AuthorType(GeneralType): + class Meta: + verbose_name = _(u"Author type") + verbose_name_plural = _(u"Author types") + +class Author(models.Model): + person = models.ForeignKey(Person, verbose_name=_(u"Person")) + author_type = models.ForeignKey(AuthorType, verbose_name=_(u"Author type")) + + class Meta: + verbose_name = _(u"Author") + verbose_name_plural = _(u"Authors") + + def __unicode__(self): + return unicode(self.person) + JOINT + unicode(self.author_type) + +class SourceType(GeneralType): + class Meta: + verbose_name = _(u"Source type") + verbose_name_plural = _(u"Source types") + +class Source(models.Model): + title = models.CharField(_(u"Title"), max_length=200) + source_type = models.ForeignKey(SourceType, verbose_name=_(u"Type")) + authors = models.ManyToManyField(Author, verbose_name=_(u"Authors")) + associated_url = models.URLField(verify_exists=False, blank=True, null=True, + verbose_name=_(u"Numerical ressource (web address)")) + receipt_date = models.DateField(blank=True, null=True, + verbose_name=_(u"Receipt date")) + creation_date = models.DateField(blank=True, null=True, + verbose_name=_(u"Creation date")) + TABLE_COLS = ['title', 'source_type', 'authors',] + + class Meta: + abstract = True + + def __unicode__(self): + return self.title + +class FileType(GeneralType): + class Meta: + verbose_name = _(u"Archaeological file type") + verbose_name_plural = _(u"Archaeological file types") + + @classmethod + def is_preventive(cls, file_type_id, key=''): + key = key or 'preventive' + try: + preventive = FileType.objects.get(txt_idx=key).pk + return file_type_id == preventive + except ObjectDoesNotExist: + return False + +class PermitType(GeneralType): + class Meta: + verbose_name = _(u"Permit type") + verbose_name_plural = _(u"Permit types") + +if settings.COUNTRY == 'fr': + class SaisineType(GeneralType): + delay = models.IntegerField(_(u"Delay (in days)")) + class Meta: + verbose_name = u"Type Saisine" + verbose_name_plural = u"Types Saisine" + +class File(BaseHistorizedItem, OwnPerms): + TABLE_COLS = ['numeric_reference', 'year', 'internal_reference', + 'file_type', 'saisine_type', 'towns', ] + year = models.IntegerField(_(u"Year"), + default=lambda:datetime.datetime.now().year) + numeric_reference = models.IntegerField(_(u"Numeric reference")) + internal_reference = models.CharField(_(u"Internal reference"), + max_length=60, unique=True) + file_type = models.ForeignKey(FileType, verbose_name=_(u"File type")) + in_charge = models.ForeignKey(Person, related_name='+', + verbose_name=_(u"Person in charge")) + general_contractor = models.ForeignKey(Person, related_name='+', + verbose_name=_(u"General contractor"), blank=True, null=True) + town_planning_service = models.ForeignKey(Organization, related_name='+', + verbose_name=_(u"Town planning service"), blank=True, null=True) + permit_type = models.ForeignKey(PermitType, verbose_name=_(u"Permit type"), + blank=True, null=True) + permit_reference = models.CharField(_(u"Permit reference"), + max_length=60, blank=True, null=True) + end_date = models.DateField(_(u"Closing date"), null=True, blank=True) + towns = models.ManyToManyField("Town", verbose_name=_(u"Towns"), + related_name='file') + creation_date = models.DateField(_(u"Creation date"), + default=datetime.date.today) + reception_date = models.DateField(_(u'Reception date'), blank=True, + null=True) + related_file = models.ForeignKey("File", verbose_name=_(u"Related file"), + blank=True, null=True) + if settings.COUNTRY == 'fr': + saisine_type = models.ForeignKey(SaisineType, blank=True, null=True, + verbose_name= u"Type de saisine") + reference_number = models.IntegerField(_(u"Reference number"), + blank=True, null=True) + total_surface = models.IntegerField(_(u"Total surface (m²)"), + blank=True, null=True) + total_developed_surface = models.IntegerField( + _(u"Total developed surface (m²)"), blank=True, null=True) + address = models.TextField(_(u"Main address"), null=True, blank=True) + address_complement = models.TextField(_(u"Main address - complement"), + null=True, blank=True) + postal_code = models.CharField(_(u"Main address - postal code"), + max_length=10, null=True, blank=True) + comment = models.TextField(_(u"Comment"), null=True, blank=True) + history = HistoricalRecords() + + class Meta: + verbose_name = _(u"Archaeological file") + verbose_name_plural = _(u"Archaeological files") + permissions = ( + ("view_own_file", ugettext(u"Can view own Archaelogical file")), + ("add_own_file", ugettext(u"Can add own Archaelogical file")), + ("change_own_file", ugettext(u"Can change own Archaelogical file")), + ("delete_own_file", ugettext(u"Can delete own Archaelogical file")), + ) + ordering = ['-year', '-numeric_reference'] + + @classmethod + def get_years(cls): + return [res['year'] for res in list(cls.objects.values('year').annotate( + Count("id")).order_by())] + + @classmethod + def get_by_year(cls, year): + return cls.objects.filter(year=year) + + @classmethod + def get_total_number(cls): + return cls.objects.count() + + def __unicode__(self): + items = [unicode(_('Intercommunal'))] + if self.towns.count() == 1: + items[0] = unicode(self.towns.all()[0]) + items.append("-".join((unicode(self.year), + unicode(self.numeric_reference)))) + items += [unicode(getattr(self, k))[:36] + for k in ['internal_reference',] if getattr(self, k)] + return JOINT.join(items) + + @classmethod + def get_query_owns(cls, user): + return Q(history_modifier=user) & Q(end_date__isnull=True) + + def is_active(self): + return not bool(self.end_date) + + def closing(self): + if self.is_active(): + return + for item in self.history.all(): + if not item.end_date: + break + return {'date':item.history_date, + 'user':IshtarUser.objects.get(pk=item.history_modifier_id)} + + def total_surface_ha(self): + if self.total_surface: + return self.total_surface/10000.0 + + def total_developed_surface_ha(self): + if self.total_developed_surface: + return self.total_developed_surface/10000.0 + + def operation_acts(self): + acts = [] + for ope in self.operations.all(): + for act in ope.administrative_act.all(): + acts.append(act) + return acts + + def is_preventive(self): + return FileType.is_preventive(self.file_type.pk) + +class FileByDepartment(models.Model): + ''' + Database view: don't forget to create it + + create view file_department (id, department_id, file_id) as + select town."id", town."departement_id", file_towns."file_id" + from ishtar_base_town town + inner join ishtar_base_file_towns file_towns on + file_towns."town_id"=town."id" order by town."departement_id"; + CREATE RULE file_department_delete + AS ON DELETE TO file_department DO INSTEAD(); + ''' + file = models.ForeignKey(File, verbose_name=_(u"File")) + department = models.ForeignKey(Departement, verbose_name=_(u"Department"), + blank=True, null=True) + class Meta: + managed = False + db_table = 'file_department' + +class OperationType(GeneralType): + class Meta: + verbose_name = _(u"Operation type") + verbose_name_plural = _(u"Operation types") + + @classmethod + def is_preventive(cls, ope_type_id, key=''): + key = key or 'prev_excavation' + try: + preventive = OperationType.objects.get(txt_idx=key).pk + return ope_type_id == preventive + except ObjectDoesNotExist: + return False + +class RemainType(GeneralType): + class Meta: + verbose_name = _(u"Remain type") + verbose_name_plural = _(u"Remain types") + +class Operation(BaseHistorizedItem, OwnPerms): + TABLE_COLS = ['year_index', 'operation_type', 'remains', 'towns', + 'associated_file', 'start_date', 'excavation_end_date'] + start_date = models.DateField(_(u"Start date"), null=True, blank=True) + excavation_end_date = models.DateField(_(u"Excavation end date"), null=True, + blank=True) + end_date = models.DateField(_(u"Closing date"), null=True, blank=True) + in_charge = models.ForeignKey('Person', related_name='+', null=True, + blank=True, verbose_name=_(u"In charge")) + year = models.IntegerField(_(u"Year")) + operation_code = models.IntegerField(_(u"Operation code")) + associated_file = models.ForeignKey(File, related_name='operations', + verbose_name=_(u"File"), blank=True, null=True) + operation_type = models.ForeignKey(OperationType, related_name='+', + verbose_name=_(u"Operation type")) + surface = models.IntegerField(_(u"Surface (m²)"), blank=True, null=True) + remains = models.ManyToManyField("RemainType", verbose_name=_(u'Remains')) + towns = models.ManyToManyField("Town", verbose_name=_(u"Towns")) + cost = models.IntegerField(_(u"Cost (€)"), blank=True, null=True) + periods = models.ManyToManyField('Period', verbose_name=_(u"Periods")) + scheduled_man_days = models.IntegerField(_(u"Scheduled man-days"), + blank=True, null=True) + optional_man_days = models.IntegerField(_(u"Optional man-days"), + blank=True, null=True) + effective_man_days = models.IntegerField(_(u"Effective man-days"), + blank=True, null=True) + if settings.COUNTRY == 'fr': + code_patriarche = models.IntegerField(u"Code PATRIARCHE", null=True, + blank=True) + TABLE_COLS = ['code_patriarche'] + TABLE_COLS + code_dracar = models.CharField(u"Code DRACAR", max_length=10, null=True, + blank=True) + fnap_financing = models.FloatField(u"Financement FNAP (%)", + blank=True, null=True) + fnap_cost = models.IntegerField(u"Financement FNAP (€)", + blank=True, null=True) + zoning_prescription = models.NullBooleanField( + _(u"Prescription on zoning"), blank=True, null=True) + large_area_prescription = models.NullBooleanField( + _(u"Prescription on large area"), blank=True, null=True) + geoarchaeological_context_prescription = models.NullBooleanField( + _(u"Prescription on geoarchaeological context"), blank=True, null=True) + operator_reference = models.CharField(_(u"Operator reference"), + max_length=20, null=True, blank=True) + common_name = models.CharField(_(u"Generic name"), max_length=120, null=True, + blank=True) + comment = models.TextField(_(u"Comment"), null=True, blank=True) + history = HistoricalRecords() + + class Meta: + verbose_name = _(u"Operation") + verbose_name_plural = _(u"Operations") + permissions = ( + ("view_own_operation", ugettext(u"Can view own Operation")), + ("add_own_operation", ugettext(u"Can add own Operation")), + ("change_own_operation", ugettext(u"Can change own Operation")), + ("delete_own_operation", ugettext(u"Can delete own Operation")), + ) + + def __unicode__(self): + items = [unicode(_('Intercommunal'))] + if self.towns.count() == 1: + items[0] = unicode(self.towns.all()[0]) + items.append("-".join((unicode(self.year), + unicode(self.operation_code)))) + return JOINT.join(items) + + @classmethod + def get_available_operation_code(cls, year=None): + if not year: + year = datetime.date.today().year + max_val = cls.objects.filter(year=year).aggregate( + Max('operation_code'))["operation_code__max"] + return (max_val + 1) if max_val else 1 + + @classmethod + def get_years(cls): + return [res['year'] for res in list(cls.objects.values('year').annotate( + Count("id")).order_by())] + + @classmethod + def get_by_year(cls, year): + return cls.objects.filter(year=year) + + @classmethod + def get_total_number(cls): + return cls.objects.count() + + year_index_lbl = _(u"Operation code") + @property + def year_index(self): + lbl = unicode(self.operation_code) + lbl = u"%d-%s%s" % (self.year, (3-len(lbl))*"0", lbl) + return lbl + + def clean(self): + objs = self.__class__.objects.filter(year=self.year, + operation_code=self.operation_code) + if self.pk: + objs = objs.exclude(pk=self.pk) + if objs.count(): + raise ValidationError(_(u"This operation code already exists for " + u"this year")) + + def is_own(self, person): + return False + + @property + def surface_ha(self): + if self.surface: + return self.surface/10000.0 + + @property + def cost_by_m2(self): + if not self.surface or not self.cost: + return + return round(float(self.cost)/self.surface, 2) + + @property + def cost_by_m2(self): + if not self.surface or not self.cost: + return + return round(float(self.cost)/self.surface, 2) + + @classmethod + def get_query_owns(cls, user): + return Q(in_charge=user.person)|Q(history_modifier=user)\ + & Q(end_date__isnull=True) + + def is_active(self): + return not bool(self.end_date) + + def closing(self): + if self.is_active(): + return + for item in self.history.all(): + if not item.end_date: + break + return {'date':item.history_date, + 'user':IshtarUser.objects.get(pk=item.history_modifier_id)} + +def operation_post_save(sender, **kwargs): + if not kwargs['instance']: + return + operation = kwargs['instance'] + if operation.fnap_financing and operation.cost: + fnap_cost = int(float(operation.cost)/100*operation.fnap_financing) + if not operation.fnap_cost or operation.fnap_cost != fnap_cost: + operation.fnap_cost = fnap_cost + operation.save() + elif operation.fnap_cost and operation.cost: + fnap_percent = float(operation.fnap_cost)*100/operation.cost + operation.fnap_financing = fnap_percent + operation.save() +post_save.connect(operation_post_save, sender=Operation) + +class OperationByDepartment(models.Model): + ''' + Database view: don't forget to create it + + create view operation_department (id, department_id, operation_id) as + select town."id", town."departement_id", operation_towns."operation_id" + from ishtar_base_town town + inner join ishtar_base_operation_towns operation_towns on + operation_towns."town_id"=town."id" order by town."departement_id"; + CREATE RULE operation_department_delete + AS ON DELETE TO operation_department DO INSTEAD(); + ''' + operation = models.ForeignKey(Operation, verbose_name=_(u"Operation")) + department = models.ForeignKey(Departement, verbose_name=_(u"Department"), + blank=True, null=True) + class Meta: + managed = False + db_table = 'operation_department' + +class OperationSource(Source): + class Meta: + verbose_name = _(u"Operation documentation") + verbose_name_plural = _(u"Operation documentations") + operation = models.ForeignKey(Operation, verbose_name=_(u"Operation"), + related_name="source") + index = models.IntegerField(verbose_name=_(u"Index")) + TABLE_COLS = ['operation.year', 'operation.operation_code'] + \ + Source.TABLE_COLS + +class Parcel(LightHistorizedItem): + associated_file = models.ForeignKey(File, related_name='parcels', + blank=True, null=True, verbose_name=_(u"File")) + operation = models.ForeignKey(Operation, related_name='parcels', blank=True, + null=True, verbose_name=_(u"Operation")) + year = models.IntegerField(_(u"Year"), blank=True, null=True) + town = models.ForeignKey("Town", related_name='parcels', + verbose_name=_(u"Town")) + section = models.CharField(_(u"Section"), max_length=4) + parcel_number = models.CharField(_(u"Parcel number"), max_length=6) + + class Meta: + verbose_name = _(u"Parcel") + verbose_name_plural = _(u"Parcels") + + def short_label(self): + return JOINT.join([unicode(item) for item in [self.section, + self.parcel_number] if item]) + + def __unicode__(self): + return self.short_label() + + def long_label(self): + items = [unicode(self.operation or self.associated_file)] + items += [unicode(item) for item in [self.section, self.parcel_number] + if item] + return JOINT.join(items) + +class Period(GeneralType) : + order = models.IntegerField(_(u"Order")) + start_date = models.IntegerField(_(u"Start date")) + end_date = models.IntegerField(_(u"End date")) + parent = models.ForeignKey("Period", verbose_name=_(u"Parent period"), + blank=True, null=True) + + class Meta: + verbose_name = _(u"Type Period") + verbose_name_plural = _(u"Types Period") + + def __unicode__(self): + return self.label + +class DatingType(GeneralType): + class Meta: + verbose_name = _(u"Dating type") + verbose_name_plural = _(u"Dating types") + +class DatingQuality(GeneralType): + class Meta: + verbose_name = _(u"Dating quality") + verbose_name_plural = _(u"Dating qualities") + +class Dating(models.Model): + period = models.ForeignKey(Period, verbose_name=_(u"Period")) + start_date = models.IntegerField(_(u"Start date"), blank=True, null=True) + end_date = models.IntegerField(_(u"End date"), blank=True, null=True) + dating_type = models.ForeignKey(DatingType, verbose_name=_(u"Dating type"), + blank=True, null=True) + quality = models.ForeignKey(DatingQuality, verbose_name=_(u"Quality"), + blank=True, null=True) + + class Meta: + verbose_name = _(u"Dating") + verbose_name_plural = _(u"Datings") + + def __unicode__(self): + start_date = self.start_date and unicode(self.start_date) or u"" + end_date = self.end_date and unicode(self.end_date) or u"" + if not start_date and not end_date: + return unicode(self.period) + return u"%s (%s-%s)" % (self.period, start_date, end_date) + +class Unit(GeneralType): + order = models.IntegerField(_(u"Order")) + parent = models.ForeignKey("Unit", verbose_name=_(u"Parent unit"), + blank=True, null=True) + + class Meta: + verbose_name = _(u"Type Unit") + verbose_name_plural = _(u"Types Unit") + + def __unicode__(self): + return self.label + +class ActivityType(GeneralType): + order = models.IntegerField(_(u"Order")) + + class Meta: + verbose_name = _(u"Type Activity") + verbose_name_plural = _(u"Types Activity") + + def __unicode__(self): + return self.label + +class IdentificationType(GeneralType): + order = models.IntegerField(_(u"Order")) + class Meta: + verbose_name = _(u"Type Identification") + verbose_name_plural = _(u"Types Identification") + + def __unicode__(self): + return self.label + +class ContextRecord(BaseHistorizedItem, OwnPerms): + TABLE_COLS = ['parcel.town', 'operation.year', + 'operation.operation_code', + 'label', 'unit'] + if settings.COUNTRY == 'fr': + TABLE_COLS.insert(1, 'parcel.operation.code_patriarche') + parcel = models.ForeignKey(Parcel, verbose_name=_(u"Parcel"), + related_name='context_record') + operation = models.ForeignKey(Operation, verbose_name=_(u"Operation"), + related_name='context_record') + label = models.CharField(_(u"ID"), max_length=200) + description = models.TextField(_(u"Description"), blank=True, null=True) + length = models.IntegerField(_(u"Length (cm)"), blank=True, null=True) + width = models.IntegerField(_(u"Width (cm)"), blank=True, null=True) + thickness = models.IntegerField(_(u"Thickness (cm)"), blank=True, null=True) + depth = models.IntegerField(_(u"Depth (cm)"), blank=True, null=True) + location = models.CharField(_(u"Location"), blank=True, null=True, + max_length=200, + help_text=_(u"A short description of the location of the context record")) + datings = models.ManyToManyField(Dating) + unit = models.ForeignKey(Unit, verbose_name=_(u"Unit"), related_name='+', + blank=True, null=True) + has_furniture = models.NullBooleanField(u"Has furniture?", blank=True, + null=True) + filling = models.TextField(_(u"Filling"), blank=True, null=True) + interpretation = models.TextField(_(u"Interpretation"), blank=True, + null=True) + taq = models.IntegerField(_(u"TAQ"), blank=True, null=True, + help_text=_(u"\"Terminus Ante Quem\" the context record can't have been " + "created after this date")) + taq_estimated = models.IntegerField(_(u"Estimated TAQ"), blank=True, + null=True, help_text=_(u"Estimation of a \"Terminus Ante Quem\"")) + tpq = models.IntegerField(_(u"TPQ"), blank=True, null=True, + help_text=_(u"\"Terminus Post Quem\" the context record can't have been " + " created before this date")) + tpq_estimated = models.IntegerField(_(u"Estimated TPQ"), blank=True, + null=True, help_text=_(u"Estimation of a \"Terminus Post Quem\"")) + identification = models.ForeignKey(IdentificationType, blank=True, + null=True, verbose_name=_(u"Identification"),) + activity = models.ForeignKey(ActivityType,blank=True, null=True, + verbose_name=_(u"Activity"),) + history = HistoricalRecords() + + class Meta: + verbose_name = _(u"Context Record") + verbose_name_plural = _(u"Context Record") + permissions = ( + ("view_own_contextrecord", ugettext(u"Can view own Context Record")), + ("add_own_contextrecord", ugettext(u"Can add own Context Record")), + ("change_own_contextrecord", ugettext(u"Can change own Context Record")), + ("delete_own_contextrecord", ugettext(u"Can delete own Context Record")), + ) + + def __unicode__(self): + return self.short_label() + + def short_label(self): + return JOINT.join([unicode(item) for item in [self.parcel, + self.label] if item]) + + def full_label(self): + if not self.parcel.operation: + return unicode(self) + return self._real_label() or self._temp_label() + + def _real_label(self): + if not self.parcel.operation.code_patriarche: + return + return JOINT.join((self.parcel.operation.code_patriarche, + self.label)) + + def _temp_label(self): + if self.parcel.operation.code_patriarche: + return + return JOINT.join([unicode(lbl) for lbl in [self.parcel.operation.year, + self.parcel.operation.operation_code, + self.label] if lbl]) + + @classmethod + def get_years(cls): + years = set() + for res in list(cls.objects.values('operation__start_date')): + yr = res['operation__start_date'].year + years.add(yr) + return list(years) + + @classmethod + def get_by_year(cls, year): + return cls.objects.filter(operation__start_date__year=year) + + @classmethod + def get_operations(cls): + return [dct['operation__pk'] + for dct in cls.objects.values('operation__pk').distinct()] + + @classmethod + def get_by_operation(cls, operation_id): + return cls.objects.filter(operation__pk=operation_id) + + @classmethod + def get_total_number(cls): + return cls.objects.filter(operation__start_date__isnull=False).count() + +class ContextRecordSource(Source): + class Meta: + verbose_name = _(u"Context record documentation") + verbose_name_plural = _(u"Context record documentations") + context_record = models.ForeignKey(ContextRecord, + verbose_name=_(u"Context record"), related_name="source") + +class MaterialType(GeneralType): + recommendation = models.TextField(_(u"Recommendation")) + parent = models.ForeignKey("MaterialType", blank=True, null=True, + verbose_name=_(u"Parent material")) + + class Meta: + verbose_name = _(u"Material type") + verbose_name_plural = _(u"Material types") + +class BaseItem(BaseHistorizedItem, OwnPerms): + label = models.CharField(_(u"ID"), max_length=60) + description = models.TextField(_(u"Description")) + context_record = models.ForeignKey(ContextRecord, + related_name='base_items', verbose_name=_(u"Context Record")) + is_isolated = models.NullBooleanField(_(u"Is isolated?"), blank=True, + null=True) + index = models.IntegerField(u"Index", default=0) + material_index = models.IntegerField(u"Material index", default=0) + history = HistoricalRecords() + + class Meta: + verbose_name = _(u"Base item") + verbose_name_plural = _(u"Base items") + permissions = ( + ("view_own_baseitem", ugettext(u"Can view own Base item")), + ("add_own_baseitem", ugettext(u"Can add own Base item")), + ("change_own_baseitem", ugettext(u"Can change own Base item")), + ("delete_own_baseitem", ugettext(u"Can delete own Base item")), + ) + + def __unicode__(self): + return self.label + + def get_last_item(self): + #TODO: manage virtuals - property(last_item) ? + items = self.item.filter().order_by("-order").all() + return items and items[0] + + def full_label(self): + return self._real_label() or self._temp_label() + + def material_type_label(self): + item = self.get_last_item() + items = [item and unicode(item.material_type) or ''] + ope = self.context_record.operation + items += [ope.code_patriarche or \ + (unicode(ope.year) + "-" + unicode(ope.operation_code))] + items += [self.context_record.label, unicode(self.material_index)] + return JOINT.join(items) + + def _real_label(self): + if not self.context_record.parcel.operation.code_patriarche: + return + item = self.get_last_item() + lbl = item.label or self.label + return JOINT.join([unicode(it) for it in ( + self.context_record.parcel.operation.code_patriarche, + self.context_record.label, + lbl) if it]) + + def _temp_label(self): + if self.context_record.parcel.operation.code_patriarche: + return + item = self.get_last_item() + lbl = item.label or self.label + return JOINT.join([unicode(it) for it in ( + self.context_record.parcel.year, + self.index, + self.context_record.label, + lbl) if it]) + +class Item(BaseHistorizedItem, OwnPerms): + TABLE_COLS = ['label', 'material_type', 'dating.period', + 'base_items.context_record.parcel.town', + 'base_items.context_record.parcel.operation.year', + 'base_items.context_record.parcel.operation.operation_code', + 'base_items.is_isolated'] + if settings.COUNTRY == 'fr': + TABLE_COLS.insert(6, + 'base_items.context_record.parcel.operation.code_patriarche') + base_items = models.ManyToManyField(BaseItem, verbose_name=_(u"Base item"), + related_name='item') + order = models.IntegerField(_(u"Order")) + label = models.CharField(_(u"ID"), max_length=60) + description = models.TextField(_(u"Description"), blank=True, null=True) + material_type = models.ForeignKey(MaterialType, + verbose_name = _(u"Material type")) + volume = models.FloatField(_(u"Volume (l)"), blank=True, null=True) + weight = models.FloatField(_(u"Weight (g)"), blank=True, null=True) + item_number = models.IntegerField(_("Item number"), blank=True, null=True) + upstream_treatment = models.ForeignKey("Treatment", blank=True, null=True, + related_name='downstream_treatment', verbose_name=_("Upstream treatment")) + downstream_treatment = models.ForeignKey("Treatment", blank=True, null=True, + related_name='upstream_treatment', verbose_name=_("Downstream treatment")) + dating = models.ForeignKey(Dating, verbose_name=_(u"Dating")) + container = models.ForeignKey('Container', verbose_name=_(u"Container"), + blank=True, null=True, related_name='items') + history = HistoricalRecords() + + @classmethod + def get_years(cls): + years = set() + items = cls.objects.filter(downstream_treatment__isnull=True) + for item in items: + bi = item.base_items.all() + if not bi: + continue + bi = bi[0] + yr = bi.context_record.operation.start_date.year + years.add(yr) + return list(years) + + @classmethod + def get_by_year(cls, year): + return cls.objects.filter(downstream_treatment__isnull=True, + base_items__context_record__operation__start_date__year=year) + + @classmethod + def get_operations(cls): + operations = set() + items = cls.objects.filter(downstream_treatment__isnull=True) + for item in items: + bi = item.base_items.all() + if not bi: + continue + bi = bi[0] + pk = bi.context_record.operation.pk + operations.add(pk) + return list(operations) + + @classmethod + def get_by_operation(cls, operation_id): + return cls.objects.filter(downstream_treatment__isnull=True, + base_items__context_record__operation__pk=operation_id) + + @classmethod + def get_total_number(cls): + return cls.objects.filter(downstream_treatment__isnull=True).count() + + def duplicate(self, user): + dct = dict([(attr, getattr(self, attr)) for attr in ('order', 'label', + 'description', 'material_type', 'volume', 'weight', + 'item_number', 'dating')]) + dct['order'] += 1 + dct['history_modifier'] = user + new = self.__class__(**dct) + new.save() + for base_item in self.base_items.all(): + new.base_items.add(base_item) + return new + + class Meta: + verbose_name = _(u"Item") + verbose_name_plural = _(u"Items") + permissions = ( + ("view_own_item", ugettext(u"Can view own Item")), + ("add_own_item", ugettext(u"Can add own Item")), + ("change_own_item", ugettext(u"Can change own Item")), + ("delete_own_item", ugettext(u"Can delete own Item")), + ) + + def __unicode__(self): + return self.label + + def save(self, *args, **kwargs): + if not self.pk: + super(Item, self).save(*args, **kwargs) + for base_item in self.base_items.all(): + if not base_item.index: + idx = BaseItem.objects.filter(context_record=\ + base_item.context_record).aggregate(Max('index')) + base_item.index = idx and idx['index__max'] + 1 or 1 + if not base_item.material_index: + idx = BaseItem.objects.filter(context_record=\ + base_item.context_record, + item__material_type=self.material_type).aggregate( + Max('material_index')) + base_item.material_index = idx and \ + idx['material_index__max'] + 1 or 1 + base_item.save() + super(Item, self).save(*args, **kwargs) + +class ItemSource(Source): + class Meta: + verbose_name = _(u"Item documentation") + verbose_name_plural = _(u"Item documentations") + item = models.ForeignKey(Item, verbose_name=_(u"Item"), + related_name="source") + +class ParcelOwner(LightHistorizedItem): + owner = models.ForeignKey(Person, verbose_name=_(u"Owner")) + parcel = models.ForeignKey(Parcel, verbose_name=_(u"Parcel")) + start_date = models.DateField(_(u"Start date")) + end_date = models.DateField(_(u"End date")) + + class Meta: + verbose_name = _(u"Parcel owner") + verbose_name_plural = _(u"Parcel owners") + + def __unicode__(self): + return self.owner + JOINT + self.parcel + +class WarehouseType(GeneralType): + class Meta: + verbose_name = _(u"Warehouse type") + verbose_name_plural = _(u"Warehouse types") + +class Warehouse(Address, OwnPerms): + name = models.CharField(_(u"Name"), max_length=40) + warehouse_type = models.ForeignKey(WarehouseType, + verbose_name=_(u"Warehouse type")) + person_in_charge = models.ForeignKey(Person, + verbose_name=_(u"Person in charge"), null=True, blank=True) + comment = models.TextField(_(u"Comment"), null=True, blank=True) + + class Meta: + verbose_name = _(u"Warehouse") + verbose_name_plural = _(u"Warehouses") + permissions = ( + ("view_own_warehouse", ugettext(u"Can view own Warehouse")), + ("add_own_warehouse", ugettext(u"Can add own Warehouse")), + ("change_own_warehouse", ugettext(u"Can change own Warehouse")), + ("delete_own_warehouse", ugettext(u"Can delete own Warehouse")), + ) + + def __unicode__(self): + return u"%s (%s)" % (self.name, unicode(self.warehouse_type)) + +class ActType(GeneralType): + TYPE = (('F', _(u'Archaelogical file')), + ('O', _(u'Operation')), + ) + intented_to = models.CharField(_(u"Intended to"), max_length=1, + choices=TYPE) + class Meta: + verbose_name = _(u"Act type") + verbose_name_plural = _(u"Act types") + +class AdministrativeAct(BaseHistorizedItem, OwnPerms): + TABLE_COLS = ['act_type', 'associated_file', 'operation', + 'associated_file.towns', 'operation.towns'] + TABLE_COLS_FILE = ['act_type', 'associated_file', 'associated_file.towns',] + TABLE_COLS_OPE = ['act_type', 'operation', 'operation.towns'] + act_type = models.ForeignKey(ActType, verbose_name=_(u"Act type")) + in_charge = models.ForeignKey(Person, blank=True, null=True, + related_name='+', verbose_name=_(u"Person in charge of the operation")) + operator = models.ForeignKey(Organization, blank=True, null=True, + verbose_name=_(u"Archaeological preventive operator")) + scientific = models.ForeignKey(Person, blank=True, null=True, +related_name='+', verbose_name=_(u"Person in charge of the scientific part")) + signatory = models.ForeignKey(Person, blank=True, null=True, + related_name='+', verbose_name=_(u"Signatory")) + operation = models.ForeignKey(Operation, blank=True, null=True, + related_name='administrative_act', verbose_name=_(u"Operation")) + associated_file = models.ForeignKey(File, blank=True, null=True, + related_name='administrative_act', verbose_name=_(u"Archaelogical file")) + signature_date = models.DateField(_(u"Signature date"), blank=True, + null=True) + act_object = models.CharField(_(u"Object"), max_length=200) + if settings.COUNTRY == 'fr': + ref_sra = models.CharField(u"Référence SRA", max_length=15) + history = HistoricalRecords() + + class Meta: + verbose_name = _(u"Administrative act") + verbose_name_plural = _(u"Administrative acts") + permissions = ( +("view_own_administrativeact", ugettext(u"Can view own Administrative act")), +("add_own_administrativeact", ugettext(u"Can add own Administrative act")), +("change_own_administrativeact", ugettext(u"Can change own Administrative act")), +("delete_own_administrativeact", ugettext(u"Can delete own Administrative act")), + ) + + def __unicode__(self): + return JOINT.join([unicode(item) + for item in [self.operation, self.associated_file, self.act_object] + if item]) + +class ContainerType(GeneralType): + length = models.IntegerField(_(u"Length (mm)"), blank=True, null=True) + width = models.IntegerField(_(u"Width (mm)"), blank=True, null=True) + height = models.IntegerField(_(u"Height (mm)"), blank=True, null=True) + volume = models.IntegerField(_(u"Volume (l)"), blank=True, null=True) + reference = models.CharField(_(u"Reference"), max_length=30) + + class Meta: + verbose_name = _(u"Container type") + verbose_name_plural = _(u"Container types") + +class Container(LightHistorizedItem): + TABLE_COLS = ['reference', 'container_type', 'location',] + location = models.ForeignKey(Warehouse, verbose_name=_(u"Warehouse")) + container_type = models.ForeignKey(ContainerType, + verbose_name=_("Container type")) + reference = models.CharField(_(u"Reference"), max_length=40) + comment = models.TextField(_(u"Comment")) + + class Meta: + verbose_name = _(u"Container") + verbose_name_plural = _(u"Containers") + + def __unicode__(self): + lbl = u" - ".join((self.reference, unicode(self.container_type), + unicode(self.location))) + return lbl + +if settings.COUNTRY == 'fr': + class Arrondissement(models.Model): + name = models.CharField(u"Nom", max_length=30) + department = models.ForeignKey(Departement, verbose_name=u"Département") + + def __unicode__(self): + return JOINT.join((self.name, unicode(self.department))) + + class Canton(models.Model): + name = models.CharField(u"Nom", max_length=30) + arrondissement = models.ForeignKey(Arrondissement, + verbose_name=u"Arrondissement") + def __unicode__(self): + return JOINT.join((self.name, unicode(self.arrondissement))) + +class Town(models.Model): + name = models.CharField(_(u"Name"), max_length=100) + surface = models.IntegerField(_(u"Surface (m²)"), blank=True, null=True) + center = models.PointField(_(u"Localisation"), srid=settings.SRID, + blank=True, null=True) + if settings.COUNTRY == 'fr': + numero_insee = models.CharField(u"Numéro INSEE", max_length=6, + unique=True) + departement = models.ForeignKey(Departement, verbose_name=u"Département", + null=True, blank=True) + canton = models.ForeignKey(Canton, verbose_name=u"Canton", null=True, + blank=True) + objects = models.GeoManager() + + class Meta: + verbose_name = _(u"Town") + verbose_name_plural = _(u"Towns") + if settings.COUNTRY == 'fr': + ordering = ['numero_insee'] + + def __unicode__(self): + if settings.COUNTRY == "fr": + return u"%s (%s)" % (self.name, self.numero_insee) + return self.name + +class TreatmentType(GeneralType): + virtual = models.BooleanField(_(u"Virtual")) + class Meta: + verbose_name = _(u"Treatment type") + verbose_name_plural = _(u"Treatment types") + +class Treatment(BaseHistorizedItem, OwnPerms): + container = models.ForeignKey(Container, verbose_name=_(u"Container"), + blank=True, null=True) + description = models.TextField(_(u"Description"), blank=True, null=True) + treatment_type = models.ForeignKey(TreatmentType, + verbose_name=_(u"Treatment type")) + location = models.ForeignKey(Warehouse, verbose_name=_(u"Location"), + blank=True, null=True) + person = models.ForeignKey(Person, verbose_name=_(u"Person"), + blank=True, null=True) + start_date = models.DateField(_(u"Start date"), blank=True, null=True) + end_date = models.DateField(_(u"End date"), blank=True, null=True) + history = HistoricalRecords() + + class Meta: + verbose_name = _(u"Treatment") + verbose_name_plural = _(u"Treatments") + permissions = ( + ("view_own_treatment", ugettext(u"Can view own Treatment")), + ("add_own_treatment", ugettext(u"Can add own Treatment")), + ("change_own_treatment", ugettext(u"Can change own Treatment")), + ("delete_own_treatment", ugettext(u"Can delete own Treatment")), + ) + + def __unicode__(self): + lbl = unicode(self.treatment_type) + if self.person: + lbl += u" %s %s" % (_(u"by"), unicode(self.person)) + return lbl + +class TreatmentSource(Source): + class Meta: + verbose_name = _(u"Treatment documentation") + verbose_name_plural = _(u"Treament documentations") + treatment = models.ForeignKey(Treatment, verbose_name=_(u"Treatment"), + related_name="source") + +class Property(LightHistorizedItem): + item = models.ForeignKey(Item, verbose_name=_(u"Item")) + administrative_act = models.ForeignKey(AdministrativeAct, + verbose_name=_(u"Administrative act")) + person = models.ForeignKey(Person, verbose_name=_(u"Person")) + start_date = models.DateField(_(u"Start date")) + end_date = models.DateField(_(u"End date")) + + class Meta: + verbose_name = _(u"Property") + verbose_name_plural = _(u"Properties") + + def __unicode__(self): + return self.person + JOINT + self.item + diff --git a/ishtar_common/scripts/__init__.py b/ishtar_common/scripts/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/ishtar_common/scripts/__init__.py diff --git a/ishtar_common/scripts/import_from_csv.py b/ishtar_common/scripts/import_from_csv.py new file mode 100755 index 000000000..de916be6f --- /dev/null +++ b/ishtar_common/scripts/import_from_csv.py @@ -0,0 +1,68 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Import departements and towns from csv file +""" + +DELIMITER = "," +QUOTECHAR = '"' + +import sys +import csv +sys.path.append('.') + +from django.core.management import setup_environ +import settings + +setup_environ(settings) + +from optparse import OptionParser + +from ishtar_base import models + +def insert_department(value): + idx, label = value + if models.Departement.objects.filter(number=idx).count(): + return + models.Departement(number=idx, label=label).save() + print idx, label, u" inserted" + +def insert_town(value): + idx, label = value + if models.Town.objects.filter(numero_insee=idx).count(): + return + try: + dpt = models.Departement.objects.get(number=idx[:2]) + except: + return + models.Town(numero_insee=idx, name=label, departement=dpt).save() + print idx, label, u" inserted" + +tables = {u"department":insert_department, + u"town":insert_town} + +usage = u"usage: %%prog csv_file.csv table_name\n\n"\ + u"Table name must be in: %s." % u", ".join(tables.keys()) +parser = OptionParser(usage=usage) + +(options, args) = parser.parse_args() + +try: + assert len(args) == 2 +except AssertionError: + parser.error(u"You must provide one csv file and the table name.") + +try: + assert args[1] in tables.keys() +except AssertionError: + parser.error(u"Incorrect table name.") + +try: + values = csv.reader(open(args[0], 'rb'), delimiter=DELIMITER, + quotechar=QUOTECHAR) +except (IOError): + parser.error(u"Incorrect CSV file.") + +for value in values: + tables[args[1]](value) diff --git a/ishtar_common/scripts/import_ope_from_csv.py b/ishtar_common/scripts/import_ope_from_csv.py new file mode 100755 index 000000000..fd29fd3f6 --- /dev/null +++ b/ishtar_common/scripts/import_ope_from_csv.py @@ -0,0 +1,411 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Scripts +""" + +DELIMITER = ";" +QUOTECHAR = '"' + +import sys +import datetime +import csv, codecs +sys.path.append('.') + +from django.core.management import setup_environ +import settings + +setup_environ(settings) + +from optparse import OptionParser + +from ishtar_base import models + +usage = u"usage: % %prog csv_file.csv update sra_nantes" +parser = OptionParser(usage=usage) + +(options, args) = parser.parse_args() + +try: + assert len(args) >= 1 +except AssertionError: + parser.error(u"You must provide one csv file.") + +update = True if len(args) > 1 and args[1] else False + +def unicode_csv_reader(unicode_csv_data, dialect=csv.excel, **kwargs): + # csv.py doesn't do Unicode; encode temporarily as UTF-8: + csv_reader = csv.reader(utf_8_encoder(unicode_csv_data), + dialect=dialect, **kwargs) + for row in csv_reader: + # decode UTF-8 back to Unicode, cell by cell: + yield [unicode(cell, 'utf-8') for cell in row] + +def utf_8_encoder(unicode_csv_data): + for line in unicode_csv_data: + yield line.encode('utf-8') + +try: + values = unicode_csv_reader(codecs.open(args[0], 'rb', "utf-8"), + delimiter=DELIMITER, quotechar=QUOTECHAR) +except (IOError): + parser.error(u"Incorrect CSV file.") + +from django.db import transaction + +from ishtar_base.models import Operation, OperationType, User, Town,\ + Person, PersonType, Period, AdministrativeAct, ActType + +# lbl, txt_idx +TYPES = { + u"SU":(u'emergency_excavation', u"Sauvetage urgent"), + u"EV":(u'evaluation', u"Évaluation"), + u"SD":(u'Sampling', u"Sondage"), + u"FP":(u"prog_excavation", u"Fouille programmée"), + u"SP":(u"prev_excavation", u"Fouille préventive"), + u"OPD":(u"arch_diagnostic", u"Diagnostic") +} + +for k in TYPES.keys(): + try: + TYPES[k] = OperationType.objects.get(txt_idx=TYPES[k][0]) + except: + ot = OperationType(txt_idx=TYPES[k][0], label=TYPES[k][1]) + ot.save() + TYPES[k] = ot + +def parse_operationtype(value): + if value not in TYPES: + return None + return TYPES[value] + +# lbl, txt_idx +PERIODS = { + u'MA':u'middle_age', + u'IND':u'indetermined', + u'CON':u'contemporan', + u'MOD':u'modern', + u'REC':u'recent_times', + u'BMA':u'low_middle_age', + u'MAC':u'classic_middle_age', + u'HMA':u'high_middle_age', + u'BAS':u'low_empire', + u'HAU':u'high-empire', + u'NRE':u'republic', + u'GAL':u'gallo-roman', + u'FE2':u'second_iron_age', + u'FE1':u'first_iron_age', + u'BRF':u'final_bronze_age', + u'BRM':u'middle_bronze_age', + u'BRA':u'old_bronze_age', + u'FER':u'iron_age', + u'BRO':u'bronze_age', + u'PRO':u'protohistory', + u'NEF':u'final_neolithic', + u'NER':u'recent_neolithic', + u'NEM':u'middle_neolithic', + u'NEA':u'old_neolithic', + u'NEO':u'neolithic', + u'MER':u'recent_mesolithic', + u'MEM':u'middle_mesolithic', + u'MEA':u'old_mesolithic', + u'MES':u'mesolithic', + u'PAF':u'final_paleolithic', + u'PAS':u'late_paleolithic', + u'PAM':u'middle_paleolithic', + u'PAA':u'ancien_paleolithic', + u'PAL':u'paleolithic', + u'':u'not_yet_documented', +} +for k in PERIODS.keys(): + PERIODS[k] = Period.objects.get(txt_idx=PERIODS[k]) +PERIODS_KEYS = PERIODS.keys() +PERIODS_KEYS.sort(key=len) +PERIODS_KEYS.reverse() + +def parse_period(value): + value = value[3:] if value.startswith('EUR') else value + while value.endswith('-'): + value = value[:-1] + value = value[3:] if value.startswith('EUR') else value + if not value: + return [PERIODS[u'']] + periods, old_val = [], u'' + while value and old_val != value: + old_val = value + for k in PERIODS_KEYS: + if value.startswith(k): + periods.append(PERIODS[k]) + value = value[len(k):] + break + return periods + +def parse_date(value): + try: + return datetime.datetime.strptime(value, '%d/%m/%Y') + except: + return None + +def parse_surface(value): + value = value.replace(',', '.') + try: + # hectare en metre carrés + value = float(value) * 10000 + if value: + return value + return None + except: + return None + +def parse_year(value): + try: + yr = int(value) + except: + return + if yr < 1900 or yr > 2100: + return + return yr + +default_person = User.objects.get(pk=2) + + +# si pas de start date : premier janvier de year + +# attrs, convert +COLS = [ + [], # numéro de dossier ? + (('operation_type',), parse_operationtype), + (('common_name',), unicode), + (('in_charge', 'name'), unicode), + (('in_charge', 'surname'), unicode), + [], # État ? + [], # Adresse ? + [], # origine ? + (('periods',), parse_period), + [], # Programme ? + [], # Rattach PC ? + [], # vide + (('administrative_act', 'ref_sra'), unicode), + (('administrative_act', 'signature_date'), parse_date), + (('start_date',), parse_date), + (('excavation_end_date',), parse_date), + (('year',), parse_year), + [], # identification + (('code_patriarche',), int), + [], # X degré + [], # Y degré + [], # X saisi ? + [], # Y saisi ? + [], # georef + [], # geometrie + (('surface',), parse_surface), +] + +def parse_insee(value): + values = [] + while len(value) > 4: + values.append(value[:5]) + value = value[5:] + towns = [] + for value in values: + try: + town = Town.objects.get(numero_insee=value) + towns.append(town) + except: + sys.stderr.write('Numero INSEE : %s non existant en base' % value) + return towns + +def parse_patriarche(value): + if not value: + return + return '18' + unicode(value) + +COLS_SRA_NANTES = [ + [], + [], + [], #(('year',), int), + (('towns',), parse_insee), + [], # Intit TODO + [], # Adresse site... TODO + [], # prog/prev + [], #(('in_charge', 'attached_to', 'name'), unicode), + [], #(('in_charge', 'name'), unicode), + [], #(('in_charge' num + [], #(('in_charge', 'surname'), unicode), + [], # num ope non patriarche + (('start_date__year',), int), + (('excavation_end_date__year',), int), + (('start_date__day',), int), + (('excavation_end_date__day',), int), + (('start_date__month',), int), + (('excavation_end_date__month',), int), + [], + [], + [], + [], + [('code_patriarche',), parse_patriarche] +] + +col_defs = COLS_SRA_NANTES if len(args) > 2 and args[2] else COLS + +ope_default = {'history_modifier':default_person} + +# key : (class, default, reverse, extra) +key_classes = { +'in_charge':(Person, {'history_modifier':default_person, + 'title':'', + 'person_type':PersonType.objects.get( + txt_idx='head_scientist')}, False), +'administrative_act':(AdministrativeAct, {'history_modifier':default_person, + 'act_type':ActType.objects.get( + txt_idx='excavation_order')}, 'operation'), +} + +@transaction.commit_manually +def import_operations(col_defs=COLS, update=False): + new_ops = 0 + error_ope, error_reversed, error_multis = [], [], [] + for line_idx, vals in enumerate(values): + sys.stdout.write("\r* line %d" % (line_idx)) + if not line_idx: + continue # remove header + args = {} + for col_idx, val in enumerate(vals): + if len(col_defs) <= col_idx or not col_defs[col_idx]: + continue + attrs, typ = col_defs[col_idx] + c_args = args + for attr in attrs: + if attr not in c_args: + c_args[attr] = {} + c_args = c_args[attr] + try: + v = typ(val) + except: + v = "" + if len(attrs) == 1: + args[attrs[0]] = v + elif len(attrs) == 2: + args[attrs[0]][attrs[1]] = v + elif len(attrs) == 3: + args[attrs[0]][attrs[1]][attrs[2]] = v + # manage exploded dates + for k in args.keys(): + if '__year' in k: + key = k[:-len('__year')] + try: + v = datetime.datetime(args[k], args[key+'__month'], + args[key+'__day']) + args[key] = v + except: + pass + args.pop(k) + args.pop(key+'__month') + args.pop(key+'__day') + reversed_items, multis = [], [] + for k in args.keys(): + if k in key_classes: + cls, default, reverse = key_classes[k] + default.update(args[k]) + if reverse: + reversed_items.append((cls, default, reverse)) + args.pop(k) + continue + try: + obj = cls.objects.get(**default) + except: + obj = cls.objects.create(**default) + obj.save() + transaction.commit() + args[k] = obj + elif type(args[k]) == list: + multis.append((k, args[k])) + args.pop(k) + op = None + if not update and not args['operation_type']: + continue + try: + op = Operation.objects.get(code_patriarche=args['code_patriarche']) + if not update: + continue + except: + if update: + continue + # creation + if not op: + args.update(ope_default) + args['operation_code'] = Operation.get_available_operation_code( + args['year']) + try: + op = Operation.objects.create(**args) + op.save() + new_ops += 1 + except: + error_ope.append((line_idx, args)) + transaction.rollback() + continue + transaction.commit() + else: # mise à jour + try: + for k in args: + if getattr(op, k): + continue + setattr(op, k, args[k]) + op.save() + except: + transaction.rollback() + continue + transaction.commit() + try: + for cls, default, reverse in reversed_items: + default[reverse] = op + it = cls(**default).save() + except: + transaction.rollback() + error_reversed.append((line_idx, reversed_items)) + continue + transaction.commit() + try: + for k, vals in multis: + for v in vals: + getattr(op, k).add(v) + op.save() + except: + transaction.rollback() + error_multis.append((line_idx, multis)) + continue + transaction.commit() + + if error_ope: + sys.stderr.write("\nError while recording theses operations:\n") + for line_idx, args in error_ope: + sys.stderr.write("line: " + str(line_idx) + " args: " + str(args) + '\n') + if error_multis: + sys.stderr.write( "\nError while recording theses multiples items attached to operation:") + for line_idx, args in error_multis: + sys.stderr.write("line: " + str(line_idx) + " args: " + str(args) + '\n') + if error_reversed: + sys.stderr.write("\nError while recording theses items that depend to operation:") + for line_idx, args in error_reversed: + sys.stderr.write("line: " + str(line_idx) + " args: " + str(args) + '\n') + + sys.stdout.write("\n%d new operations recorded\n" % new_ops) + +import_operations(col_defs=col_defs, update=update) diff --git a/ishtar_common/scripts/import_towns_from_osm.py b/ishtar_common/scripts/import_towns_from_osm.py new file mode 100755 index 000000000..fb301f09f --- /dev/null +++ b/ishtar_common/scripts/import_towns_from_osm.py @@ -0,0 +1,110 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +Import towns from OpenStreetMap data. +Take an OSM xml file for argument. + +To get an OSM file (with a bounding box adapted to your needs): +curl --location --globoff "http://www.informationfreeway.org/api/0.6/node[place=village|town|city][bbox=-5.53711,41.90228,8.96484,51.50874]" -o city.osm +or from a whole xml/pbf export: +./osmosis --read-pbf ~/france-20110125.osm.pbf --node-key-value keyValueList="place.village,place.town,place.city" --write-xml city.osm +""" + +import sys +sys.path.append('.') + +from django.core.management import setup_environ +from django.core.exceptions import ObjectDoesNotExist +from django.contrib.gis.geos import Point +import settings + +setup_environ(settings) + +from optparse import OptionParser +from xml.parsers import expat + +from ishtar_base import models + +usage = "usage: %prog osm_file.xml" +parser = OptionParser(usage=usage) + +(options, args) = parser.parse_args() + +try: + assert len(args) == 1 +except AssertionError: + parser.error("You must provide one XML file") + + +ATTRS = [u"lat", u"lon"] + +# key : (mandatory, [restraint to keys]) +TAGS = {u"place":(True, [u"village", u"town", u"city"]), + u"ref:INSEE":(True, []), + u"population":(False, []) + } + +class TownParser: + + def __init__(self): + self._parser = expat.ParserCreate() + self._parser.returns_unicode = True + self._parser.StartElementHandler = self.start + self._parser.EndElementHandler = self.end + self._parser.CharacterDataHandler = self.data + self.town = {} + self.number = 0 + + def feed(self, data): + self._parser.ParseFile(data) + + def close(self): + self._parser.Parse("", 1) # end of data + del self._parser # get rid of circular references + + def start(self, tag, attrs): + if tag == u"node": + self.town = {} + for attr in ATTRS: + if attr in attrs: + self.town[attr] = attrs[attr] + if tag == u"tag": + if not u"k" in attrs or not u"v" in attrs: + return + if attrs[u"k"] in TAGS: + limit = TAGS[attrs[u"k"]][1] + if limit and \ + (attrs[u"v"] not in limit or \ + (type(limit) == unicode and limit not in attrs[u"v"])): + self.town["DEL"] = True + return + self.town[attrs[u"k"]] = attrs[u"v"] + + def end(self, tag): + if tag == u"node" and self.town and "DEL" not in self.town: + for k in TAGS: + if TAGS[k][0] and k not in self.town: + return + self.number += 1 + try: + town = models.Town.objects.get(numero_insee=self.town["ref:INSEE"]) + except ObjectDoesNotExist: + return + town.center = Point(float(self.town['lon']), float(self.town['lat']), + srid=4326) + town.save() + print town, "updated" + + def data(self, data): + pass + +p = TownParser() + +try: + p.feed(file(args[0])) + print u"%d towns updated" % p.number +except (IOError, expat.ExpatError): + parser.error("Incorrect XML file") + + diff --git a/ishtar_common/static/js/i18n/grid.locale-bg.js b/ishtar_common/static/js/i18n/grid.locale-bg.js new file mode 100644 index 000000000..00d9583df --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-bg.js @@ -0,0 +1,132 @@ +;(function($){
+/**
+ * jqGrid Bulgarian Translation
+ * Tony Tomov tony@trirand.com
+ * http://trirand.com/blog/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "{0} - {1} от {2}",
+ emptyrecords: "Няма запис(и)",
+ loadtext: "Зареждам...",
+ pgtext : "Стр. {0} от {1}"
+ },
+ search : {
+ caption: "Търсене...",
+ Find: "Намери",
+ Reset: "Изчисти",
+ odata : ['равно', 'различно', 'по-малко', 'по-малко или=','по-голямо','по-голямо или =', 'започва с','не започва с','се намира в','не се намира в','завършва с','не завършава с','съдържа', 'не съдържа' ],
+ groupOps: [ { op: "AND", text: " И " }, { op: "OR", text: "ИЛИ" } ],
+ matchText: " включи",
+ rulesText: " клауза"
+ },
+ edit : {
+ addCaption: "Нов Запис",
+ editCaption: "Редакция Запис",
+ bSubmit: "Запиши",
+ bCancel: "Изход",
+ bClose: "Затвори",
+ saveData: "Данните са променени! Да съхраня ли промените?",
+ bYes : "Да",
+ bNo : "Не",
+ bExit : "Отказ",
+ msg: {
+ required:"Полето е задължително",
+ number:"Въведете валидно число!",
+ minValue:"стойността трябва да е по-голяма или равна от",
+ maxValue:"стойността трябва да е по-малка или равна от",
+ email: "не е валиден ел. адрес",
+ integer: "Въведете валидно цяло число",
+ date: "Въведете валидна дата",
+ url: "e невалиден URL. Изискава се префикс('http://' или 'https://')",
+ nodefined : " е недефинирана!",
+ novalue : " изисква връщане на стойност!",
+ customarray : "Потреб. Функция трябва да върне масив!",
+ customfcheck : "Потребителска функция е задължителна при този тип елемент!"
+ }
+ },
+ view : {
+ caption: "Преглед запис",
+ bClose: "Затвори"
+ },
+ del : {
+ caption: "Изтриване",
+ msg: "Да изтрия ли избраният запис?",
+ bSubmit: "Изтрий",
+ bCancel: "Отказ"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Редакция избран запис",
+ addtext:" ",
+ addtitle: "Добавяне нов запис",
+ deltext: " ",
+ deltitle: "Изтриване избран запис",
+ searchtext: " ",
+ searchtitle: "Търсене запис(и)",
+ refreshtext: "",
+ refreshtitle: "Обнови таблица",
+ alertcap: "Предупреждение",
+ alerttext: "Моля, изберете запис",
+ viewtext: "",
+ viewtitle: "Преглед избран запис"
+ },
+ col : {
+ caption: "Избери колони",
+ bSubmit: "Ок",
+ bCancel: "Изход"
+ },
+ errors : {
+ errcap : "Грешка",
+ nourl : "Няма посочен url адрес",
+ norecords: "Няма запис за обработка",
+ model : "Модела не съответства на имената!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:" лв.", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "Нед", "Пон", "Вт", "Ср", "Чет", "Пет", "Съб",
+ "Неделя", "Понеделник", "Вторник", "Сряда", "Четвъртък", "Петък", "Събота"
+ ],
+ monthNames: [
+ "Яну", "Фев", "Мар", "Апр", "Май", "Юни", "Юли", "Авг", "Сеп", "Окт", "Нов", "Дек",
+ "Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"
+ ],
+ AmPm : ["","","",""],
+ S: function (j) {
+ if(j==7 || j==8 || j== 27 || j== 28) {
+ return 'ми';
+ }
+ return ['ви', 'ри', 'ти'][Math.min((j - 1) % 10, 2)];
+ },
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-bg1251.js b/ishtar_common/static/js/i18n/grid.locale-bg1251.js new file mode 100644 index 000000000..058950e62 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-bg1251.js @@ -0,0 +1,132 @@ +;(function($){
+/**
+ * jqGrid Bulgarian Translation
+ * Tony Tomov tony@trirand.com
+ * http://trirand.com/blog/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "{0} - {1} {2}",
+ emptyrecords: " ()",
+ loadtext: "...",
+ pgtext : ". {0} {1}"
+ },
+ search : {
+ caption: "...",
+ Find: "",
+ Reset: "",
+ odata : ['', '', '-', '- =','-','- =', ' ',' ',' ',' ',' ',' ','', ' ' ],
+ groupOps: [ { op: "AND", text: " " }, { op: "OR", text: "" } ],
+ matchText: " ",
+ rulesText: " "
+ },
+ edit : {
+ addCaption: " ",
+ editCaption: " ",
+ bSubmit: "",
+ bCancel: "",
+ bClose: "",
+ saveData: " ! ?",
+ bYes : "",
+ bNo : "",
+ bExit : "",
+ msg: {
+ required:" ",
+ number:" !",
+ minValue:" - ",
+ maxValue:" - ",
+ email: " . ",
+ integer: " ",
+ date: " ",
+ url: "e URL. ('http://' 'https://')",
+ nodefined : " !",
+ novalue : " !",
+ customarray : ". !",
+ customfcheck : " !"
+ }
+ },
+ view : {
+ caption: " ",
+ bClose: ""
+ },
+ del : {
+ caption: "",
+ msg: " ?",
+ bSubmit: "",
+ bCancel: ""
+ },
+ nav : {
+ edittext: " ",
+ edittitle: " ",
+ addtext:" ",
+ addtitle: " ",
+ deltext: " ",
+ deltitle: " ",
+ searchtext: " ",
+ searchtitle: " ()",
+ refreshtext: "",
+ refreshtitle: " ",
+ alertcap: "",
+ alerttext: ", ",
+ viewtext: "",
+ viewtitle: " "
+ },
+ col : {
+ caption: " ",
+ bSubmit: "",
+ bCancel: ""
+ },
+ errors : {
+ errcap : "",
+ nourl : " url ",
+ norecords: " ",
+ model : " !"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:" .", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "", "", "", "", "", "", "",
+ "", "", "", "", "", "", ""
+ ],
+ monthNames: [
+ "", "", "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "", "", ""
+ ],
+ AmPm : ["","","",""],
+ S: function (j) {
+ if(j==7 || j==8 || j== 27 || j== 28) {
+ return '';
+ }
+ return ['', '', ''][Math.min((j - 1) % 10, 2)];
+ },
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-cat.js b/ishtar_common/static/js/i18n/grid.locale-cat.js new file mode 100644 index 000000000..76215f60f --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-cat.js @@ -0,0 +1,128 @@ +;(function($){
+/**
+ * jqGrid Catalan Translation
+ * Traducció jqGrid en Catatà per Faserline, S.L.
+ * http://www.faserline.com
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Mostrant {0} - {1} de {2}",
+ emptyrecords: "Sense registres que mostrar",
+ loadtext: "Carregant...",
+ pgtext : "Pàgina {0} de {1}"
+ },
+ search : {
+ caption: "Cerca...",
+ Find: "Cercar",
+ Reset: "Buidar",
+ odata : ['equal', 'not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is in','is not in','ends with','does not end with','contains','does not contain'],
+ groupOps: [ { op: "AND", text: "tot" }, { op: "OR", text: "qualsevol" } ],
+ matchText: " match",
+ rulesText: " rules"
+ },
+ edit : {
+ addCaption: "Afegir registre",
+ editCaption: "Modificar registre",
+ bSubmit: "Guardar",
+ bCancel: "Cancelar",
+ bClose: "Tancar",
+ saveData: "Les dades han canviat. Guardar canvis?",
+ bYes : "Yes",
+ bNo : "No",
+ bExit : "Cancel",
+ msg: {
+ required:"Camp obligatori",
+ number:"Introdueixi un nombre",
+ minValue:"El valor ha de ser major o igual que ",
+ maxValue:"El valor ha de ser menor o igual a ",
+ email: "no és una direcció de correu vàlida",
+ integer: "Introdueixi un valor enter",
+ date: "Introdueixi una data correcta ",
+ url: "no és una URL vàlida. Prefix requerit ('http://' or 'https://')",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+ }
+ },
+ view : {
+ caption: "Veure registre",
+ bClose: "Tancar"
+ },
+ del : {
+ caption: "Eliminar",
+ msg: "¿Desitja eliminar els registres seleccionats?",
+ bSubmit: "Eliminar",
+ bCancel: "Cancelar"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Modificar fila seleccionada",
+ addtext:" ",
+ addtitle: "Agregar nova fila",
+ deltext: " ",
+ deltitle: "Eliminar fila seleccionada",
+ searchtext: " ",
+ searchtitle: "Cercar informació",
+ refreshtext: "",
+ refreshtitle: "Refrescar taula",
+ alertcap: "Avís",
+ alerttext: "Seleccioni una fila",
+ viewtext: " ",
+ viewtitle: "Veure fila seleccionada"
+ },
+// setcolumns module
+ col : {
+ caption: "Mostrar/ocultar columnes",
+ bSubmit: "Enviar",
+ bCancel: "Cancelar"
+ },
+ errors : {
+ errcap : "Error",
+ nourl : "No s'ha especificat una URL",
+ norecords: "No hi ha dades per processar",
+ model : "Les columnes de noms són diferents de les columnes del model"
+ },
+ formatter : {
+ integer : {thousandsSeparator: ".", defaultValue: '0'},
+ number : {decimalSeparator:",", thousandsSeparator: ".", decimalPlaces: 2, defaultValue: '0,00'},
+ currency : {decimalSeparator:",", thousandsSeparator: ".", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0,00'},
+ date : {
+ dayNames: [
+ "Dg", "Dl", "Dt", "Dc", "Dj", "Dv", "Ds",
+ "Diumenge", "Dilluns", "Dimarts", "Dimecres", "Dijous", "Divendres", "Dissabte"
+ ],
+ monthNames: [
+ "Gen", "Febr", "Març", "Abr", "Maig", "Juny", "Jul", "Ag", "Set", "Oct", "Nov", "Des",
+ "Gener", "Febrer", "Març", "Abril", "Maig", "Juny", "Juliol", "Agost", "Setembre", "Octubre", "Novembre", "Desembre"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'd-m-Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: 'show',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-cn.js b/ishtar_common/static/js/i18n/grid.locale-cn.js new file mode 100644 index 000000000..e2f282c71 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-cn.js @@ -0,0 +1,132 @@ +;(function($){
+/**
+ * jqGrid Chinese Translation for v3.6
+ * waiting 2010.01.18
+ * http://waiting.javaeye.com/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * update 2010.05.04
+ * add double u3000 SPACE for search:odata to fix SEARCH box display err when narrow width from only use of eq/ne/cn/in/lt/gt operator under IE6/7
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "{0} - {1}\u3000共 {2} 条", // 共字前是全角空格
+ emptyrecords: "无数据显示",
+ loadtext: "读取中...",
+ pgtext : " {0} 共 {1} 页"
+ },
+ search : {
+ caption: "搜索...",
+ Find: "查找",
+ Reset: "重置",
+ odata : ['等于\u3000\u3000', '不等\u3000\u3000', '小于\u3000\u3000', '小于等于','大于\u3000\u3000','大于等于',
+ '开始于','不开始于','属于\u3000\u3000','不属于','结束于','不结束于','包含\u3000\u3000','不包含'],
+ groupOps: [ { op: "AND", text: "所有" }, { op: "OR", text: "任一" } ],
+ matchText: " 匹配",
+ rulesText: " 规则"
+ },
+ edit : {
+ addCaption: "添加记录",
+ editCaption: "编辑记录",
+ bSubmit: "提交",
+ bCancel: "取消",
+ bClose: "关闭",
+ saveData: "数据已改变,是否保存?",
+ bYes : "是",
+ bNo : "否",
+ bExit : "取消",
+ msg: {
+ required:"此字段必需",
+ number:"请输入有效数字",
+ minValue:"输值必须大于等于 ",
+ maxValue:"输值必须小于等于 ",
+ email: "这不是有效的e-mail地址",
+ integer: "请输入有效整数",
+ date: "请输入有效时间",
+ url: "无效网址。前缀必须为 ('http://' 或 'https://')",
+ nodefined : " 未定义!",
+ novalue : " 需要返回值!",
+ customarray : "自定义函数需要返回数组!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+
+ }
+ },
+ view : {
+ caption: "查看记录",
+ bClose: "关闭"
+ },
+ del : {
+ caption: "删除",
+ msg: "删除所选记录?",
+ bSubmit: "删除",
+ bCancel: "取消"
+ },
+ nav : {
+ edittext: "",
+ edittitle: "编辑所选记录",
+ addtext:"",
+ addtitle: "添加新记录",
+ deltext: "",
+ deltitle: "删除所选记录",
+ searchtext: "",
+ searchtitle: "查找",
+ refreshtext: "",
+ refreshtitle: "刷新表格",
+ alertcap: "注意",
+ alerttext: "请选择记录",
+ viewtext: "",
+ viewtitle: "查看所选记录"
+ },
+ col : {
+ caption: "选择列",
+ bSubmit: "确定",
+ bCancel: "取消"
+ },
+ errors : {
+ errcap : "错误",
+ nourl : "没有设置url",
+ norecords: "没有要处理的记录",
+ model : "colNames 和 colModel 长度不等!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat",
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'm-d-Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "Y/j/n",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-cs.js b/ishtar_common/static/js/i18n/grid.locale-cs.js new file mode 100644 index 000000000..ad3cfc310 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-cs.js @@ -0,0 +1,128 @@ +;(function($){
+/**
+ * jqGrid Czech Translation
+ * Pavel Jirak pavel.jirak@jipas.cz
+ * doplnil Thomas Wagner xwagne01@stud.fit.vutbr.cz
+ * http://trirand.com/blog/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Zobrazeno {0} - {1} z {2} záznamů",
+ emptyrecords: "Nenalezeny žádné záznamy",
+ loadtext: "Načítám...",
+ pgtext : "Strana {0} z {1}"
+ },
+ search : {
+ caption: "Vyhledávám...",
+ Find: "Hledat",
+ Reset: "Reset",
+ odata : ['rovno', 'nerovono', 'menší', 'menší nebo rovno','větší', 'větší nebo rovno', 'začíná s', 'nezačíná s', 'je v', 'není v', 'končí s', 'nekončí s', 'obahuje', 'neobsahuje'],
+ groupOps: [ { op: "AND", text: "všech" }, { op: "OR", text: "některého z" } ],
+ matchText: " hledat podle",
+ rulesText: " pravidel"
+ },
+ edit : {
+ addCaption: "Přidat záznam",
+ editCaption: "Editace záznamu",
+ bSubmit: "Uložit",
+ bCancel: "Storno",
+ bClose: "Zavřít",
+ saveData: "Data byla změněna! Uložit změny?",
+ bYes : "Ano",
+ bNo : "Ne",
+ bExit : "Zrušit",
+ msg: {
+ required:"Pole je vyžadováno",
+ number:"Prosím, vložte validní číslo",
+ minValue:"hodnota musí být větší než nebo rovná ",
+ maxValue:"hodnota musí být menší než nebo rovná ",
+ email: "není validní e-mail",
+ integer: "Prosím, vložte celé číslo",
+ date: "Prosím, vložte validní datum",
+ url: "není platnou URL. Vyžadován prefix ('http://' or 'https://')",
+ nodefined : " není definován!",
+ novalue : " je vyžadována návratová hodnota!",
+ customarray : "Custom function mělá vrátit pole!",
+ customfcheck : "Custom function by měla být přítomna v případě custom checking!"
+ }
+ },
+ view : {
+ caption: "Zobrazit záznam",
+ bClose: "Zavřít"
+ },
+ del : {
+ caption: "Smazat",
+ msg: "Smazat vybraný(é) záznam(y)?",
+ bSubmit: "Smazat",
+ bCancel: "Storno"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Editovat vybraný řádek",
+ addtext:" ",
+ addtitle: "Přidat nový řádek",
+ deltext: " ",
+ deltitle: "Smazat vybraný záznam ",
+ searchtext: " ",
+ searchtitle: "Najít záznamy",
+ refreshtext: "",
+ refreshtitle: "Obnovit tabulku",
+ alertcap: "Varování",
+ alerttext: "Prosím, vyberte řádek",
+ viewtext: "",
+ viewtitle: "Zobrazit vybraný řádek"
+ },
+ col : {
+ caption: "Zobrazit/Skrýt sloupce",
+ bSubmit: "Uložit",
+ bCancel: "Storno"
+ },
+ errors : {
+ errcap : "Chyba",
+ nourl : "Není nastavena url",
+ norecords: "Žádné záznamy ke zpracování",
+ model : "Délka colNames <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "Ne", "Po", "Út", "St", "Čt", "Pá", "So",
+ "Neděle", "Pondělí", "Úterý", "Středa", "Čtvrtek", "Pátek", "Sobota"
+ ],
+ monthNames: [
+ "Led", "Úno", "Bře", "Dub", "Kvě", "Čer", "Čvc", "Srp", "Zář", "Říj", "Lis", "Pro",
+ "Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"
+ ],
+ AmPm : ["do","od","DO","OD"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-da.js b/ishtar_common/static/js/i18n/grid.locale-da.js new file mode 100644 index 000000000..44e745f61 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-da.js @@ -0,0 +1,128 @@ +;(function($){
+/**
+ * jqGrid Danish Translation
+ * Aesiras A/S
+ * http://www.aesiras.dk
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Vis {0} - {1} of {2}",
+ emptyrecords: "Ingen linjer fundet",
+ loadtext: "Henter...",
+ pgtext : "Side {0} af {1}"
+ },
+ search : {
+ caption: "Søg...",
+ Find: "Find",
+ Reset: "Nulstil",
+ odata : ['lig', 'forskellige fra', 'mindre', 'mindre eller lig','større','større eller lig', 'begynder med','begynder ikke med','findes i','findes ikke i','ender med','ender ikke med','indeholder','indeholder ikke'],
+ groupOps: [ { op: "AND", text: "all" }, { op: "OR", text: "any" } ],
+ matchText: " lig",
+ rulesText: " regler"
+ },
+ edit : {
+ addCaption: "Tilføj",
+ editCaption: "Ret",
+ bSubmit: "Send",
+ bCancel: "Annuller",
+ bClose: "Luk",
+ saveData: "Data er ændret. Gem data?",
+ bYes : "Ja",
+ bNo : "Nej",
+ bExit : "Fortryd",
+ msg: {
+ required:"Felt er nødvendigt",
+ number:"Indtast venligst et validt tal",
+ minValue:"værdi skal være større end eller lig med",
+ maxValue:"værdi skal være mindre end eller lig med",
+ email: "er ikke en gyldig email",
+ integer: "Indtast venligst et gyldigt heltal",
+ date: "Indtast venligst en gyldig datoværdi",
+ url: "er ugyldig URL. Prefix mangler ('http://' or 'https://')",
+ nodefined : " er ikke defineret!",
+ novalue : " returværdi kræves!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+ }
+ },
+ view : {
+ caption: "Vis linje",
+ bClose: "Luk"
+ },
+ del : {
+ caption: "Slet",
+ msg: "Slet valgte linje(r)?",
+ bSubmit: "Slet",
+ bCancel: "Fortryd"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Rediger valgte linje",
+ addtext:" ",
+ addtitle: "Tilføj ny linje",
+ deltext: " ",
+ deltitle: "Slet valgte linje",
+ searchtext: " ",
+ searchtitle: "Find linjer",
+ refreshtext: "",
+ refreshtitle: "Indlæs igen",
+ alertcap: "Advarsel",
+ alerttext: "Vælg venligst linje",
+ viewtext: "",
+ viewtitle: "Vis valgte linje"
+ },
+ col : {
+ caption: "Vis/skjul kolonner",
+ bSubmit: "Opdatere",
+ bCancel: "Fortryd"
+ },
+ errors : {
+ errcap : "Fejl",
+ nourl : "Ingen url valgt",
+ norecords: "Ingen linjer at behandle",
+ model : "colNames og colModel har ikke samme længde!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0,00'},
+ currency : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0,00'},
+ date : {
+ dayNames: [
+ "Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør",
+ "Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec",
+ "Januar", "Februar", "Marts", "April", "Maj", "Juni", "Juli", "August", "September", "Oktober", "November", "December"
+ ],
+ AmPm : ["","","",""],
+ S: function (j) {return '.'},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "j/n/Y",
+ LongDate: "l d. F Y",
+ FullDateTime: "l d F Y G:i:s",
+ MonthDay: "d. F",
+ ShortTime: "G:i",
+ LongTime: "G:i:s",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+// DA
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-de.js b/ishtar_common/static/js/i18n/grid.locale-de.js new file mode 100644 index 000000000..106e8992a --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-de.js @@ -0,0 +1,133 @@ +;(function($){
+/**
+ * jqGrid German Translation
+ * Version 1.0.0 (developed for jQuery Grid 3.3.1)
+ * Olaf Klöppel opensource@blue-hit.de
+ * http://blue-hit.de/
+ *
+ * Updated for jqGrid 3.8
+ * Andreas Flack
+ * http://www.contentcontrol-berlin.de
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Zeige {0} - {1} von {2}",
+ emptyrecords: "Keine Datensätze vorhanden",
+ loadtext: "Lädt...",
+ pgtext : "Seite {0} von {1}"
+ },
+ search : {
+ caption: "Suche...",
+ Find: "Suchen",
+ Reset: "Zurücksetzen",
+ odata : ['gleich', 'ungleich', 'kleiner', 'kleiner gleich','größer','größer gleich', 'beginnt mit','beginnt nicht mit','ist in','ist nicht in','endet mit','endet nicht mit','enthält','enthält nicht'],
+ groupOps: [ { op: "AND", text: "alle" }, { op: "OR", text: "mindestens eine" } ],
+ matchText: " erfülle",
+ rulesText: " Bedingung(en)"
+ },
+ edit : {
+ addCaption: "Datensatz hinzufügen",
+ editCaption: "Datensatz bearbeiten",
+ bSubmit: "Speichern",
+ bCancel: "Abbrechen",
+ bClose: "Schließen",
+ saveData: "Daten wurden geändert! Änderungen speichern?",
+ bYes : "ja",
+ bNo : "nein",
+ bExit : "abbrechen",
+ msg: {
+ required:"Feld ist erforderlich",
+ number: "Bitte geben Sie eine Zahl ein",
+ minValue:"Wert muss größer oder gleich sein, als ",
+ maxValue:"Wert muss kleiner oder gleich sein, als ",
+ email: "ist keine gültige E-Mail-Adresse",
+ integer: "Bitte geben Sie eine Ganzzahl ein",
+ date: "Bitte geben Sie ein gültiges Datum ein",
+ url: "ist keine gültige URL. Präfix muss eingegeben werden ('http://' oder 'https://')",
+ nodefined : " ist nicht definiert!",
+ novalue : " Rückgabewert ist erforderlich!",
+ customarray : "Benutzerdefinierte Funktion sollte ein Array zurückgeben!",
+ customfcheck : "Benutzerdefinierte Funktion sollte im Falle der benutzerdefinierten Überprüfung vorhanden sein!"
+ }
+ },
+ view : {
+ caption: "Datensatz anzeigen",
+ bClose: "Schließen"
+ },
+ del : {
+ caption: "Löschen",
+ msg: "Ausgewählte Datensätze löschen?",
+ bSubmit: "Löschen",
+ bCancel: "Abbrechen"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Ausgewählte Zeile editieren",
+ addtext:" ",
+ addtitle: "Neue Zeile einfügen",
+ deltext: " ",
+ deltitle: "Ausgewählte Zeile löschen",
+ searchtext: " ",
+ searchtitle: "Datensatz suchen",
+ refreshtext: "",
+ refreshtitle: "Tabelle neu laden",
+ alertcap: "Warnung",
+ alerttext: "Bitte Zeile auswählen",
+ viewtext: "",
+ viewtitle: "Ausgewählte Zeile anzeigen"
+ },
+ col : {
+ caption: "Spalten auswählen",
+ bSubmit: "Speichern",
+ bCancel: "Abbrechen"
+ },
+ errors : {
+ errcap : "Fehler",
+ nourl : "Keine URL angegeben",
+ norecords: "Keine Datensätze zu bearbeiten",
+ model : "colNames und colModel sind unterschiedlich lang!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: ".", defaultValue: '0'},
+ number : {decimalSeparator:",", thousandsSeparator: ".", decimalPlaces: 2, defaultValue: '0,00'},
+ currency : {decimalSeparator:",", thousandsSeparator: ".", decimalPlaces: 2, prefix: "", suffix:" €", defaultValue: '0,00'},
+ date : {
+ dayNames: [
+ "So", "Mo", "Di", "Mi", "Do", "Fr", "Sa",
+ "Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Mar", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez",
+ "Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return 'ter'},
+ srcformat: 'Y-m-d',
+ newformat: 'd.m.Y',
+ masks : {
+ ISO8601Long: "Y-m-d H:i:s",
+ ISO8601Short: "Y-m-d",
+ ShortDate: "j.n.Y",
+ LongDate: "l, j. F Y",
+ FullDateTime: "l, d. F Y G:i:s",
+ MonthDay: "d. F",
+ ShortTime: "G:i",
+ LongTime: "G:i:s",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
\ No newline at end of file diff --git a/ishtar_common/static/js/i18n/grid.locale-el.js b/ishtar_common/static/js/i18n/grid.locale-el.js new file mode 100644 index 000000000..d4f642328 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-el.js @@ -0,0 +1,126 @@ +;(function($){
+/**
+ * jqGrid Greek (el) Translation
+ * Alex Cicovic
+ * http://www.alexcicovic.com
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "View {0} - {1} of {2}",
+ emptyrecords: "No records to view",
+ loadtext: "Φόρτωση...",
+ pgtext : "Page {0} of {1}"
+ },
+ search : {
+ caption: "Αναζήτηση...",
+ Find: "Εύρεση",
+ Reset: "Επαναφορά",
+ odata : ['equal', 'not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is in','is not in','ends with','does not end with','contains','does not contain'],
+ groupOps: [ { op: "AND", text: "all" }, { op: "OR", text: "any" } ],
+ matchText: " match",
+ rulesText: " rules"
+ },
+ edit : {
+ addCaption: "Εισαγωγή Εγγραφής",
+ editCaption: "Επεξεργασία Εγγραφής",
+ bSubmit: "Καταχώρηση",
+ bCancel: "Άκυρο",
+ bClose: "Κλείσιμο",
+ saveData: "Data has been changed! Save changes?",
+ bYes : "Yes",
+ bNo : "No",
+ bExit : "Cancel",
+ msg: {
+ required:"Το πεδίο είναι απαραίτητο",
+ number:"Το πεδίο δέχεται μόνο αριθμούς",
+ minValue:"Η τιμή πρέπει να είναι μεγαλύτερη ή ίση του ",
+ maxValue:"Η τιμή πρέπει να είναι μικρότερη ή ίση του ",
+ email: "Η διεύθυνση e-mail δεν είναι έγκυρη",
+ integer: "Το πεδίο δέχεται μόνο ακέραιους αριθμούς",
+ url: "is not a valid URL. Prefix required ('http://' or 'https://')",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+ }
+ },
+ view : {
+ caption: "View Record",
+ bClose: "Close"
+ },
+ del : {
+ caption: "Διαγραφή",
+ msg: "Διαγραφή των επιλεγμένων εγγραφών;",
+ bSubmit: "Ναι",
+ bCancel: "Άκυρο"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Επεξεργασία επιλεγμένης εγγραφής",
+ addtext:" ",
+ addtitle: "Εισαγωγή νέας εγγραφής",
+ deltext: " ",
+ deltitle: "Διαγραφή επιλεγμένης εγγραφής",
+ searchtext: " ",
+ searchtitle: "Εύρεση Εγγραφών",
+ refreshtext: "",
+ refreshtitle: "Ανανέωση Πίνακα",
+ alertcap: "Προσοχή",
+ alerttext: "Δεν έχετε επιλέξει εγγραφή",
+ viewtext: "",
+ viewtitle: "View selected row"
+ },
+ col : {
+ caption: "Εμφάνιση / Απόκρυψη Στηλών",
+ bSubmit: "ΟΚ",
+ bCancel: "Άκυρο"
+ },
+ errors : {
+ errcap : "Σφάλμα",
+ nourl : "Δεν έχει δοθεί διεύθυνση χειρισμού για τη συγκεκριμένη ενέργεια",
+ norecords: "Δεν υπάρχουν εγγραφές προς επεξεργασία",
+ model : "Άνισος αριθμός πεδίων colNames/colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ",
+ "Κυριακή", "Δευτέρα", "Τρίτη", "Τετάρτη", "Πέμπτη", "Παρασκευή", "Σάββατο"
+ ],
+ monthNames: [
+ "Ιαν", "Φεβ", "Μαρ", "Απρ", "Μαι", "Ιουν", "Ιουλ", "Αυγ", "Σεπ", "Οκτ", "Νοε", "Δεκ",
+ "Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"
+ ],
+ AmPm : ["πμ","μμ","ΠΜ","ΜΜ"],
+ S: function (j) {return j == 1 || j > 1 ? ['η'][Math.min((j - 1) % 10, 3)] : ''},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-en.js b/ishtar_common/static/js/i18n/grid.locale-en.js new file mode 100644 index 000000000..64dc885c9 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-en.js @@ -0,0 +1,128 @@ +;(function($){
+/**
+ * jqGrid English Translation
+ * Tony Tomov tony@trirand.com
+ * http://trirand.com/blog/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "View {0} - {1} of {2}",
+ emptyrecords: "No records to view",
+ loadtext: "Loading...",
+ pgtext : "Page {0} of {1}"
+ },
+ search : {
+ caption: "Search...",
+ Find: "Find",
+ Reset: "Reset",
+ odata : ['equal', 'not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is in','is not in','ends with','does not end with','contains','does not contain'],
+ groupOps: [ { op: "AND", text: "all" }, { op: "OR", text: "any" } ],
+ matchText: " match",
+ rulesText: " rules"
+ },
+ edit : {
+ addCaption: "Add Record",
+ editCaption: "Edit Record",
+ bSubmit: "Submit",
+ bCancel: "Cancel",
+ bClose: "Close",
+ saveData: "Data has been changed! Save changes?",
+ bYes : "Yes",
+ bNo : "No",
+ bExit : "Cancel",
+ msg: {
+ required:"Field is required",
+ number:"Please, enter valid number",
+ minValue:"value must be greater than or equal to ",
+ maxValue:"value must be less than or equal to",
+ email: "is not a valid e-mail",
+ integer: "Please, enter valid integer value",
+ date: "Please, enter valid date value",
+ url: "is not a valid URL. Prefix required ('http://' or 'https://')",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+
+ }
+ },
+ view : {
+ caption: "View Record",
+ bClose: "Close"
+ },
+ del : {
+ caption: "Delete",
+ msg: "Delete selected record(s)?",
+ bSubmit: "Delete",
+ bCancel: "Cancel"
+ },
+ nav : {
+ edittext: "",
+ edittitle: "Edit selected row",
+ addtext:"",
+ addtitle: "Add new row",
+ deltext: "",
+ deltitle: "Delete selected row",
+ searchtext: "",
+ searchtitle: "Find records",
+ refreshtext: "",
+ refreshtitle: "Reload Grid",
+ alertcap: "Warning",
+ alerttext: "Please, select row",
+ viewtext: "",
+ viewtitle: "View selected row"
+ },
+ col : {
+ caption: "Select columns",
+ bSubmit: "Ok",
+ bCancel: "Cancel"
+ },
+ errors : {
+ errcap : "Error",
+ nourl : "No url is set",
+ norecords: "No records to process",
+ model : "Length of colNames <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat",
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-es.js b/ishtar_common/static/js/i18n/grid.locale-es.js new file mode 100644 index 000000000..3d997378b --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-es.js @@ -0,0 +1,128 @@ +;(function($){
+/**
+ * jqGrid Spanish Translation
+ * Traduccion jqGrid en Español por Yamil Bracho
+ * Traduccion corregida y ampliada por Faserline, S.L.
+ * http://www.faserline.com
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Mostrando {0} - {1} de {2}",
+ emptyrecords: "Sin registros que mostrar",
+ loadtext: "Cargando...",
+ pgtext : "Página {0} de {1}"
+ },
+ search : {
+ caption: "Búsqueda...",
+ Find: "Buscar",
+ Reset: "Limpiar",
+ odata : ['igual ', 'no igual a', 'menor que', 'menor o igual que','mayor que','mayor o igual a', 'empiece por','no empiece por','está en','no está en','termina por','no termina por','contiene','no contiene'],
+ groupOps: [ { op: "AND", text: "todo" }, { op: "OR", text: "cualquier" } ],
+ matchText: " match",
+ rulesText: " reglas"
+ },
+ edit : {
+ addCaption: "Agregar registro",
+ editCaption: "Modificar registro",
+ bSubmit: "Guardar",
+ bCancel: "Cancelar",
+ bClose: "Cerrar",
+ saveData: "Se han modificado los datos, ¿guardar cambios?",
+ bYes : "Si",
+ bNo : "No",
+ bExit : "Cancelar",
+ msg: {
+ required:"Campo obligatorio",
+ number:"Introduzca un número",
+ minValue:"El valor debe ser mayor o igual a ",
+ maxValue:"El valor debe ser menor o igual a ",
+ email: "no es una dirección de correo válida",
+ integer: "Introduzca un valor entero",
+ date: "Introduza una fecha correcta ",
+ url: "no es una URL válida. Prefijo requerido ('http://' or 'https://')",
+ nodefined : " no está definido.",
+ novalue : " valor de retorno es requerido.",
+ customarray : "La función personalizada debe devolver un array.",
+ customfcheck : "La función personalizada debe estar presente en el caso de validación personalizada."
+ }
+ },
+ view : {
+ caption: "Consultar registro",
+ bClose: "Cerrar"
+ },
+ del : {
+ caption: "Eliminar",
+ msg: "¿Desea eliminar los registros seleccionados?",
+ bSubmit: "Eliminar",
+ bCancel: "Cancelar"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Modificar fila seleccionada",
+ addtext:" ",
+ addtitle: "Agregar nueva fila",
+ deltext: " ",
+ deltitle: "Eliminar fila seleccionada",
+ searchtext: " ",
+ searchtitle: "Buscar información",
+ refreshtext: "",
+ refreshtitle: "Recargar datos",
+ alertcap: "Aviso",
+ alerttext: "Seleccione una fila",
+ viewtext: "",
+ viewtitle: "Ver fila seleccionada"
+ },
+ col : {
+ caption: "Mostrar/ocultar columnas",
+ bSubmit: "Enviar",
+ bCancel: "Cancelar"
+ },
+ errors : {
+ errcap : "Error",
+ nourl : "No se ha especificado una URL",
+ norecords: "No hay datos para procesar",
+ model : "Las columnas de nombres son diferentes de las columnas de modelo"
+ },
+ formatter : {
+ integer : {thousandsSeparator: ".", defaultValue: '0'},
+ number : {decimalSeparator:",", thousandsSeparator: ".", decimalPlaces: 2, defaultValue: '0,00'},
+ currency : {decimalSeparator:",", thousandsSeparator: ".", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0,00'},
+ date : {
+ dayNames: [
+ "Do", "Lu", "Ma", "Mi", "Ju", "Vi", "Sa",
+ "Domingo", "Lunes", "Martes", "Miercoles", "Jueves", "Viernes", "Sabado"
+ ],
+ monthNames: [
+ "Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic",
+ "Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'd-m-Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-fa.js b/ishtar_common/static/js/i18n/grid.locale-fa.js new file mode 100644 index 000000000..3c233de6b --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-fa.js @@ -0,0 +1,145 @@ +;(function ($) {
+/**
+ * jqGrid Persian Translation
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+ $.jgrid = {
+ defaults: {
+ recordtext: "نمابش {0} - {1} از {2}",
+ emptyrecords: "رکوردی یافت نشد",
+ loadtext: "بارگزاري...",
+ pgtext: "صفحه {0} از {1}"
+ },
+ search: {
+ caption: "جستجو...",
+ Find: "يافته ها",
+ Reset: "از نو",
+ odata: ['برابر', 'نا برابر', 'به', 'کوچکتر', 'از', 'بزرگتر', 'شروع با', 'شروع نشود با', 'نباشد', 'عضو این نباشد', 'اتمام با', 'تمام نشود با', 'حاوی', 'نباشد حاوی'],
+ groupOps: [{
+ op: "AND",
+ text: "کل"
+ },
+ {
+ op: "OR",
+ text: "مجموع"
+ }],
+ matchText: " حاوی",
+ rulesText: " اطلاعات"
+ },
+ edit: {
+ addCaption: "اضافه کردن رکورد",
+ editCaption: "ويرايش رکورد",
+ bSubmit: "ثبت",
+ bCancel: "انصراف",
+ bClose: "بستن",
+ saveData: "دیتا تعییر کرد! ذخیره شود؟",
+ bYes: "بله",
+ bNo: "خیر",
+ bExit: "انصراف",
+ msg: {
+ required: "فيلدها بايد ختما پر شوند",
+ number: "لطفا عدد وعتبر وارد کنيد",
+ minValue: "مقدار وارد شده بايد بزرگتر يا مساوي با",
+ maxValue: "مقدار وارد شده بايد کوچکتر يا مساوي",
+ email: "پست الکترونيک وارد شده معتبر نيست",
+ integer: "لطفا يک عدد صحيح وارد کنيد",
+ date: "لطفا يک تاريخ معتبر وارد کنيد",
+ url: "این آدرس صحیح نمی باشد. پیشوند نیاز است ('http://' یا 'https://')",
+ nodefined: " تعریف نشده!",
+ novalue: " مقدار برگشتی اجباری است!",
+ customarray: "تابع شما باید مقدار آرایه داشته باشد!",
+ customfcheck: "برای داشتن متد دلخواه شما باید سطون با چکینگ دلخواه داشته باشید!"
+ }
+ },
+ view: {
+ caption: "نمایش رکورد",
+ bClose: "بستن"
+ },
+ del: {
+ caption: "حذف",
+ msg: "از حذف گزينه هاي انتخاب شده مطمئن هستيد؟",
+ bSubmit: "حذف",
+ bCancel: "ابطال"
+ },
+ nav: {
+ edittext: " ",
+ edittitle: "ويرايش رديف هاي انتخاب شده",
+ addtext: " ",
+ addtitle: "افزودن رديف جديد",
+ deltext: " ",
+ deltitle: "حذف ردبف هاي انتخاب شده",
+ searchtext: " ",
+ searchtitle: "جستجوي رديف",
+ refreshtext: "",
+ refreshtitle: "بازيابي مجدد صفحه",
+ alertcap: "اخطار",
+ alerttext: "لطفا يک رديف انتخاب کنيد",
+ viewtext: "",
+ viewtitle: "نمایش رکورد های انتخاب شده"
+ },
+ col: {
+ caption: "نمايش/عدم نمايش ستون",
+ bSubmit: "ثبت",
+ bCancel: "انصراف"
+ },
+ errors: {
+ errcap: "خطا",
+ nourl: "هيچ آدرسي تنظيم نشده است",
+ norecords: "هيچ رکوردي براي پردازش موجود نيست",
+ model: "طول نام ستون ها محالف ستون هاي مدل مي باشد!"
+ },
+ formatter: {
+ integer: {
+ thousandsSeparator: " ",
+ defaultValue: "0"
+ },
+ number: {
+ decimalSeparator: ".",
+ thousandsSeparator: " ",
+ decimalPlaces: 2,
+ defaultValue: "0.00"
+ },
+ currency: {
+ decimalSeparator: ".",
+ thousandsSeparator: " ",
+ decimalPlaces: 2,
+ prefix: "",
+ suffix: "",
+ defaultValue: "0"
+ },
+ date: {
+ dayNames: ["يک", "دو", "سه", "چهار", "پنج", "جمع", "شنب", "يکشنبه", "دوشنبه", "سه شنبه", "چهارشنبه", "پنجشنبه", "جمعه", "شنبه"],
+ monthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "ژانويه", "فوريه", "مارس", "آوريل", "مه", "ژوئن", "ژوئيه", "اوت", "سپتامبر", "اکتبر", "نوامبر", "December"],
+ AmPm: ["ب.ظ", "ب.ظ", "ق.ظ", "ق.ظ"],
+ S: function (b) {
+ return b < 11 || b > 13 ? ["st", "nd", "rd", "th"][Math.min((b - 1) % 10, 3)] : "th"
+ },
+ srcformat: "Y-m-d",
+ newformat: "d/m/Y",
+ masks: {
+ ISO8601Long: "Y-m-d H:i:s",
+ ISO8601Short: "Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit: false
+ },
+ baseLinkUrl: "",
+ showAction: "نمايش",
+ target: "",
+ checkbox: {
+ disabled: true
+ },
+ idName: "id"
+ }
+ }
+})(jQuery);
\ No newline at end of file diff --git a/ishtar_common/static/js/i18n/grid.locale-fi.js b/ishtar_common/static/js/i18n/grid.locale-fi.js new file mode 100644 index 000000000..9a07511d9 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-fi.js @@ -0,0 +1,128 @@ +;(function($){
+/**
+ * jqGrid (fi) Finnish Translation
+ * Jukka Inkeri awot.fi 2010-05-19 Version
+ * http://awot.fi
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults: {
+ recordtext: "Rivit {0} - {1} / {2}",
+ emptyrecords: "Ei näytettäviä",
+ loadtext: "Haetaan...",
+ pgtext: "Sivu {0} / {1}"
+ },
+ search: {
+ caption: "Etsi...",
+ Find: "Etsi",
+ Reset: "Tyhjää",
+ odata: ['=', '<>', '<', '<=','>','>=', 'alkaa','ei ala','joukossa','ei joukossa','loppuu','ei lopu','sisältää','ei sisällä'],
+ groupOps: [ { op: "AND", text: "kaikki" }, { op: "OR", text: "mikä tahansa" } ],
+ matchText: " täytä ehdot:",
+ rulesText: ""
+ },
+ edit: {
+ addCaption: "Uusi rivi",
+ editCaption: "Muokkaa riviä",
+ bSubmit: "OK",
+ bCancel: "Peru",
+ bClose: "Sulje",
+ saveData: "Tietoja muutettu! Tallennetaanko?",
+ bYes: "K",
+ bNo: "E",
+ bExit: "Peru",
+ msg: {
+ required: "pakollinen",
+ number: "Anna kelvollinen nro",
+ minValue: "arvo oltava >= ",
+ maxValue: "arvo oltava <= ",
+ email: "virheellinen sposti ",
+ integer: "Anna kelvollinen kokonaisluku",
+ date: "Anna kelvollinen pvm",
+ url: "Ei ole sopiva linkki(URL). Alku oltava ('http://' tai 'https://')",
+ nodefined: " ei ole määritelty!",
+ novalue: " paluuarvo vaaditaan!",
+ customarray: "Custom function should return array!",
+ customfcheck: "Custom function should be present in case of custom checking!"
+ }
+ },
+ view: {
+ caption: "Näytä rivi",
+ bClose: "Sulje"
+ },
+ del: {
+ caption: "Poista",
+ msg: "Poista valitut rivit?",
+ bSubmit: "Poista",
+ bCancel: "Peru"
+ },
+ nav: {
+ edittext: " ",
+ edittitle: "Muokkaa valittu rivi",
+ addtext: " ",
+ addtitle: "Uusi rivi",
+ deltext: " ",
+ deltitle: "Poista valittu rivi",
+ searchtext: " ",
+ searchtitle: "Etsi tietoja",
+ refreshtext: "",
+ refreshtitle: "Lataa uudelleen",
+ alertcap: "Varoitus",
+ alerttext: "Valitse rivi",
+ viewtext: "",
+ viewtitle: "Näyta valitut rivit"
+ },
+ col: {
+ caption: "Näyta/Piilota sarakkeet",
+ bSubmit: "OK",
+ bCancel: "Peru"
+ },
+ errors : {
+ errcap: "Virhe",
+ nourl: "url asettamatta",
+ norecords: "Ei muokattavia tietoja",
+ model: "Pituus colNames <> colModel!"
+ },
+ formatter: {
+ integer: {thousandsSeparator: "", defaultValue: '0'},
+ number: {decimalSeparator:",", thousandsSeparator: "", decimalPlaces: 2, defaultValue: '0,00'},
+ currency: {decimalSeparator:",", thousandsSeparator: "", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0,00'},
+ date: {
+ dayNames: [
+ "Su", "Ma", "Ti", "Ke", "To", "Pe", "La",
+ "Sunnuntai", "Maanantai", "Tiistai", "Keskiviikko", "Torstai", "Perjantai", "Lauantai"
+ ],
+ monthNames: [
+ "Tam", "Hel", "Maa", "Huh", "Tou", "Kes", "Hei", "Elo", "Syy", "Lok", "Mar", "Jou",
+ "Tammikuu", "Helmikuu", "Maaliskuu", "Huhtikuu", "Toukokuu", "Kesäkuu", "Heinäkuu", "Elokuu", "Syyskuu", "Lokakuu", "Marraskuu", "Joulukuu"
+ ],
+ AmPm: ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks: {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "d.m.Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox: {disabled:true},
+ idName: 'id'
+ }
+};
+// FI
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-fr.js b/ishtar_common/static/js/i18n/grid.locale-fr.js new file mode 100644 index 000000000..a7d22abe7 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-fr.js @@ -0,0 +1,126 @@ +;(function($){
+/**
+ * jqGrid French Translation
+ * Tony Tomov tony@trirand.com
+ * http://trirand.com/blog/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Enregistrements {0} - {1} sur {2}",
+ emptyrecords: "Aucun enregistrement à afficher",
+ loadtext: "Chargement...",
+ pgtext : "Page {0} sur {1}"
+ },
+ search : {
+ caption: "Recherche...",
+ Find: "Chercher",
+ Reset: "Annuler",
+ odata : ['égal', 'différent', 'inférieur', 'inférieur ou égal','supérieur','supérieur ou égal', 'commence par','ne commence pas par','est dans',"n'est pas dans",'finit par','ne finit pas par','contient','ne contient pas'],
+ groupOps: [ { op: "AND", text: "tous" }, { op: "OR", text: "aucun" } ],
+ matchText: " correspondance",
+ rulesText: " règles"
+ },
+ edit : {
+ addCaption: "Ajouter",
+ editCaption: "Editer",
+ bSubmit: "Valider",
+ bCancel: "Annuler",
+ bClose: "Fermer",
+ saveData: "Les données ont changé ! Enregistrer les modifications ?",
+ bYes: "Oui",
+ bNo: "Non",
+ bExit: "Annuler",
+ msg: {
+ required: "Champ obligatoire",
+ number: "Saisissez un nombre correct",
+ minValue: "La valeur doit être supérieure ou égale à",
+ maxValue: "La valeur doit être inférieure ou égale à",
+ email: "n'est pas un email correct",
+ integer: "Saisissez un entier correct",
+ url: "n'est pas une adresse correcte. Préfixe requis ('http://' or 'https://')",
+ nodefined : " n'est pas défini!",
+ novalue : " la valeur de retour est requise!",
+ customarray : "Une fonction personnalisée devrait retourner un tableau (array)!",
+ customfcheck : "Une fonction personnalisée devrait être présente dans le cas d'une vérification personnalisée!"
+ }
+ },
+ view : {
+ caption: "Voir les enregistrement",
+ bClose: "Fermer"
+ },
+ del : {
+ caption: "Supprimer",
+ msg: "Supprimer les enregistrements sélectionnés ?",
+ bSubmit: "Supprimer",
+ bCancel: "Annuler"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Editer la ligne sélectionnée",
+ addtext:" ",
+ addtitle: "Ajouter une ligne",
+ deltext: " ",
+ deltitle: "Supprimer la ligne sélectionnée",
+ searchtext: " ",
+ searchtitle: "Chercher un enregistrement",
+ refreshtext: "",
+ refreshtitle: "Recharger le tableau",
+ alertcap: "Avertissement",
+ alerttext: "Veuillez sélectionner une ligne",
+ viewtext: "",
+ viewtitle: "Afficher la ligne sélectionnée"
+ },
+ col : {
+ caption: "Afficher/Masquer les colonnes",
+ bSubmit: "Valider",
+ bCancel: "Annuler"
+ },
+ errors : {
+ errcap : "Erreur",
+ nourl : "Aucune adresse n'est paramétrée",
+ norecords: "Aucun enregistrement à traiter",
+ model : "Nombre de titres (colNames) <> Nombre de données (colModel)!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0,00'},
+ currency : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0,00'},
+ date : {
+ dayNames: [
+ "Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam",
+ "Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"
+ ],
+ monthNames: [
+ "Jan", "Fév", "Mar", "Avr", "Mai", "Jui", "Jul", "Aou", "Sep", "Oct", "Nov", "Déc",
+ "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Aout", "Septembre", "Octobre", "Novembre", "Décembre"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j == 1 ? 'er' : 'e';},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-gl.js b/ishtar_common/static/js/i18n/grid.locale-gl.js new file mode 100644 index 000000000..a2faba2c0 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-gl.js @@ -0,0 +1,126 @@ +;(function($){
+/**
+ * jqGrid Galician Translation
+ * Translated by Jorge Barreiro <yortx.barry@gmail.com>
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Amosando {0} - {1} de {2}",
+ emptyrecords: "Sen rexistros que amosar",
+ loadtext: "Cargando...",
+ pgtext : "Páxina {0} de {1}"
+ },
+ search : {
+ caption: "Búsqueda...",
+ Find: "Buscar",
+ Reset: "Limpar",
+ odata : ['igual ', 'diferente a', 'menor que', 'menor ou igual que','maior que','maior ou igual a', 'empece por','non empece por','está en','non está en','termina por','non termina por','contén','non contén'],
+ groupOps: [ { op: "AND", text: "todo" }, { op: "OR", text: "calquera" } ],
+ matchText: " match",
+ rulesText: " regras"
+ },
+ edit : {
+ addCaption: "Engadir rexistro",
+ editCaption: "Modificar rexistro",
+ bSubmit: "Gardar",
+ bCancel: "Cancelar",
+ bClose: "Pechar",
+ saveData: "Modificáronse os datos, quere gardar os cambios?",
+ bYes : "Si",
+ bNo : "Non",
+ bExit : "Cancelar",
+ msg: {
+ required:"Campo obrigatorio",
+ number:"Introduza un número",
+ minValue:"O valor debe ser maior ou igual a ",
+ maxValue:"O valor debe ser menor ou igual a ",
+ email: "non é un enderezo de correo válido",
+ integer: "Introduza un valor enteiro",
+ date: "Introduza unha data correcta ",
+ url: "non é unha URL válida. Prefixo requerido ('http://' ou 'https://')",
+ nodefined : " non está definido.",
+ novalue : " o valor de retorno é obrigatorio.",
+ customarray : "A función persoalizada debe devolver un array.",
+ customfcheck : "A función persoalizada debe estar presente no caso de ter validación persoalizada."
+ }
+ },
+ view : {
+ caption: "Consultar rexistro",
+ bClose: "Pechar"
+ },
+ del : {
+ caption: "Eliminar",
+ msg: "Desexa eliminar os rexistros seleccionados?",
+ bSubmit: "Eliminar",
+ bCancel: "Cancelar"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Modificar a fila seleccionada",
+ addtext:" ",
+ addtitle: "Engadir unha nova fila",
+ deltext: " ",
+ deltitle: "Eliminar a fila seleccionada",
+ searchtext: " ",
+ searchtitle: "Buscar información",
+ refreshtext: "",
+ refreshtitle: "Recargar datos",
+ alertcap: "Aviso",
+ alerttext: "Seleccione unha fila",
+ viewtext: "",
+ viewtitle: "Ver fila seleccionada"
+ },
+ col : {
+ caption: "Mostrar/ocultar columnas",
+ bSubmit: "Enviar",
+ bCancel: "Cancelar"
+ },
+ errors : {
+ errcap : "Erro",
+ nourl : "Non especificou unha URL",
+ norecords: "Non hai datos para procesar",
+ model : "As columnas de nomes son diferentes das columnas de modelo"
+ },
+ formatter : {
+ integer : {thousandsSeparator: ".", defaultValue: '0'},
+ number : {decimalSeparator:",", thousandsSeparator: ".", decimalPlaces: 2, defaultValue: '0,00'},
+ currency : {decimalSeparator:",", thousandsSeparator: ".", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0,00'},
+ date : {
+ dayNames: [
+ "Do", "Lu", "Ma", "Me", "Xo", "Ve", "Sa",
+ "Domingo", "Luns", "Martes", "Mércoles", "Xoves", "Vernes", "Sábado"
+ ],
+ monthNames: [
+ "Xan", "Feb", "Mar", "Abr", "Mai", "Xuñ", "Xul", "Ago", "Set", "Out", "Nov", "Dec",
+ "Xaneiro", "Febreiro", "Marzo", "Abril", "Maio", "Xuño", "Xullo", "Agosto", "Setembro", "Outubro", "Novembro", "Decembro"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'd-m-Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-he.js b/ishtar_common/static/js/i18n/grid.locale-he.js new file mode 100644 index 000000000..e226083dd --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-he.js @@ -0,0 +1,127 @@ +;(function($){
+/**
+ * jqGrid Hebrew Translation
+ * Shuki Shukrun shukrun.shuki@gmail.com
+ * http://trirand.com/blog/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "מציג {0} - {1} מתוך {2}",
+ emptyrecords: "אין רשומות להציג",
+ loadtext: "טוען...",
+ pgtext : "דף {0} מתוך {1}"
+ },
+ search : {
+ caption: "מחפש...",
+ Find: "חפש",
+ Reset: "התחל",
+ odata : ['שווה', 'לא שווה', 'קטן', 'קטן או שווה','גדול','גדול או שווה', 'מתחיל ב','לא מתחיל ב','נמצא ב','לא נמצא ב','מסתיים ב','לא מסתיים ב','מכיל','לא מכיל'],
+ groupOps: [ { op: "AND", text: "הכל" }, { op: "OR", text: "אחד מ" } ],
+ matchText: " תואם",
+ rulesText: " חוקים"
+ },
+ edit : {
+ addCaption: "הוסף רשומה",
+ editCaption: "ערוך רשומה",
+ bSubmit: "שלח",
+ bCancel: "בטל",
+ bClose: "סגור",
+ saveData: "נתונים השתנו! לשמור?",
+ bYes : "כן",
+ bNo : "לא",
+ bExit : "בטל",
+ msg: {
+ required:"שדה חובה",
+ number:"אנא, הכנס מספר תקין",
+ minValue:"ערך צריך להיות גדול או שווה ל ",
+ maxValue:"ערך צריך להיות קטן או שווה ל ",
+ email: "היא לא כתובת איימל תקינה",
+ integer: "אנא, הכנס מספר שלם",
+ date: "אנא, הכנס תאריך תקין",
+ url: "הכתובת אינה תקינה. דרושה תחילית ('http://' או 'https://')",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+ }
+ },
+ view : {
+ caption: "הצג רשומה",
+ bClose: "סגור"
+ },
+ del : {
+ caption: "מחק",
+ msg: "האם למחוק את הרשומה/ות המסומנות?",
+ bSubmit: "מחק",
+ bCancel: "בטל"
+ },
+ nav : {
+ edittext: "",
+ edittitle: "ערוך שורה מסומנת",
+ addtext:"",
+ addtitle: "הוסף שורה חדשה",
+ deltext: "",
+ deltitle: "מחק שורה מסומנת",
+ searchtext: "",
+ searchtitle: "חפש רשומות",
+ refreshtext: "",
+ refreshtitle: "טען גריד מחדש",
+ alertcap: "אזהרה",
+ alerttext: "אנא, בחר שורה",
+ viewtext: "",
+ viewtitle: "הצג שורה מסומנת"
+ },
+ col : {
+ caption: "הצג/הסתר עמודות",
+ bSubmit: "שלח",
+ bCancel: "בטל"
+ },
+ errors : {
+ errcap : "שגיאה",
+ nourl : "לא הוגדרה כתובת url",
+ norecords: "אין רשומות לעבד",
+ model : "אורך של colNames <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "א", "ב", "ג", "ד", "ה", "ו", "ש",
+ "ראשון", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת"
+ ],
+ monthNames: [
+ "ינו", "פבר", "מרץ", "אפר", "מאי", "יונ", "יול", "אוג", "ספט", "אוק", "נוב", "דצמ",
+ "ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני", "יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר"
+ ],
+ AmPm : ["לפני הצהרים","אחר הצהרים","לפני הצהרים","אחר הצהרים"],
+ S: function (j) {return j < 11 || j > 13 ? ['', '', '', ''][Math.min((j - 1) % 10, 3)] : ''},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-hu.js b/ishtar_common/static/js/i18n/grid.locale-hu.js new file mode 100644 index 000000000..15ae3b60b --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-hu.js @@ -0,0 +1,129 @@ +;(function($){
+/**
+ * jqGrid Hungarian Translation
+ * Őrszigety Ádám udx6bs@freemail.hu
+ * http://trirand.com/blog/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+
+$.jgrid = {
+ defaults : {
+ recordtext: "Oldal {0} - {1} / {2}",
+ emptyrecords: "Nincs találat",
+ loadtext: "Betöltés...",
+ pgtext : "Oldal {0} / {1}"
+ },
+ search : {
+ caption: "Keresés...",
+ Find: "Keres",
+ Reset: "Alapértelmezett",
+ odata : ['egyenlő', 'nem egyenlő', 'kevesebb', 'kevesebb vagy egyenlő','nagyobb','nagyobb vagy egyenlő', 'ezzel kezdődik','nem ezzel kezdődik','tartalmaz','nem tartalmaz','végződik','nem végződik','tartalmaz','nem tartalmaz'],
+ groupOps: [ { op: "AND", text: "all" }, { op: "OR", text: "any" } ],
+ matchText: " match",
+ rulesText: " rules"
+ },
+ edit : {
+ addCaption: "Új tétel",
+ editCaption: "Tétel szerkesztése",
+ bSubmit: "Mentés",
+ bCancel: "Mégse",
+ bClose: "Bezárás",
+ saveData: "A tétel megváltozott! Tétel mentése?",
+ bYes : "Igen",
+ bNo : "Nem",
+ bExit : "Mégse",
+ msg: {
+ required:"Kötelező mező",
+ number:"Kérjük, adjon meg egy helyes számot",
+ minValue:"Nagyobb vagy egyenlőnek kell lenni mint ",
+ maxValue:"Kisebb vagy egyenlőnek kell lennie mint",
+ email: "hibás emailcím",
+ integer: "Kérjük adjon meg egy helyes egész számot",
+ date: "Kérjük adjon meg egy helyes dátumot",
+ url: "nem helyes cím. Előtag kötelező ('http://' vagy 'https://')",
+ nodefined : " nem definiált!",
+ novalue : " visszatérési érték kötelező!!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+
+ }
+ },
+ view : {
+ caption: "Tétel megtekintése",
+ bClose: "Bezárás"
+ },
+ del : {
+ caption: "Törlés",
+ msg: "Kiválaztott tétel(ek) törlése?",
+ bSubmit: "Törlés",
+ bCancel: "Mégse"
+ },
+ nav : {
+ edittext: "",
+ edittitle: "Tétel szerkesztése",
+ addtext:"",
+ addtitle: "Új tétel hozzáadása",
+ deltext: "",
+ deltitle: "Tétel törlése",
+ searchtext: "",
+ searchtitle: "Keresés",
+ refreshtext: "",
+ refreshtitle: "Frissítés",
+ alertcap: "Figyelmeztetés",
+ alerttext: "Kérem válasszon tételt.",
+ viewtext: "",
+ viewtitle: "Tétel megtekintése"
+ },
+ col : {
+ caption: "Oszlopok kiválasztása",
+ bSubmit: "Ok",
+ bCancel: "Mégse"
+ },
+ errors : {
+ errcap : "Hiba",
+ nourl : "Nincs URL beállítva",
+ norecords: "Nincs feldolgozásra váró tétel",
+ model : "colNames és colModel hossza nem egyenlő!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0,00'},
+ currency : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0,00'},
+ date : {
+ dayNames: [
+ "Va", "Hé", "Ke", "Sze", "Csü", "Pé", "Szo",
+ "Vasárnap", "Hétfő", "Kedd", "Szerda", "Csütörtök", "Péntek", "Szombat"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Már", "Ápr", "Máj", "Jún", "Júl", "Aug", "Szep", "Okt", "Nov", "Dec",
+ "Január", "Február", "Március", "Áprili", "Május", "Június", "Július", "Augusztus", "Szeptember", "Október", "November", "December"
+ ],
+ AmPm : ["de","du","DE","DU"],
+ S: function (j) {return '.-ik';},
+ srcformat: 'Y-m-d',
+ newformat: 'Y/m/d',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "Y/j/n",
+ LongDate: "Y. F hó d., l",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "a g:i",
+ LongTime: "a g:i:s",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "Y, F"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-is.js b/ishtar_common/static/js/i18n/grid.locale-is.js new file mode 100644 index 000000000..b586e11d8 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-is.js @@ -0,0 +1,126 @@ +;(function($){
+/**
+ * jqGrid Icelandic Translation
+ * jtm@hi.is Univercity of Iceland
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "View {0} - {1} of {2}",
+ emptyrecords: "No records to view",
+ loadtext: "Hleður...",
+ pgtext : "Page {0} of {1}"
+ },
+ search : {
+ caption: "Leita...",
+ Find: "Leita",
+ Reset: "Endursetja",
+ odata : ['equal', 'not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is in','is not in','ends with','does not end with','contains','does not contain'],
+ groupOps: [ { op: "AND", text: "all" }, { op: "OR", text: "any" } ],
+ matchText: " match",
+ rulesText: " rules"
+ },
+ edit : {
+ addCaption: "Add Record",
+ editCaption: "Edit Record",
+ bSubmit: "Vista",
+ bCancel: "Hætta við",
+ bClose: "Loka",
+ saveData: "Data has been changed! Save changes?",
+ bYes : "Yes",
+ bNo : "No",
+ bExit : "Cancel",
+ msg: {
+ required:"Reitur er nauðsynlegur",
+ number:"Vinsamlega settu inn tölu",
+ minValue:"gildi verður að vera meira en eða jafnt og ",
+ maxValue:"gildi verður að vera minna en eða jafnt og ",
+ email: "er ekki löglegt email",
+ integer: "Vinsamlega settu inn tölu",
+ date: "Please, enter valid date value",
+ url: "is not a valid URL. Prefix required ('http://' or 'https://')",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+ }
+ },
+ view : {
+ caption: "View Record",
+ bClose: "Close"
+ },
+ del : {
+ caption: "Eyða",
+ msg: "Eyða völdum færslum ?",
+ bSubmit: "Eyða",
+ bCancel: "Hætta við"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Breyta færslu",
+ addtext:" ",
+ addtitle: "Ný færsla",
+ deltext: " ",
+ deltitle: "Eyða færslu",
+ searchtext: " ",
+ searchtitle: "Leita",
+ refreshtext: "",
+ refreshtitle: "Endurhlaða",
+ alertcap: "Viðvörun",
+ alerttext: "Vinsamlega veldu færslu",
+ viewtext: "",
+ viewtitle: "View selected row"
+ },
+ col : {
+ caption: "Sýna / fela dálka",
+ bSubmit: "Vista",
+ bCancel: "Hætta við"
+ },
+ errors : {
+ errcap : "Villa",
+ nourl : "Vantar slóð",
+ norecords: "Engar færslur valdar",
+ model : "Length of colNames <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "Sun", "Mon", "Tue", "Wed", "Thr", "Fri", "Sat",
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-it.js b/ishtar_common/static/js/i18n/grid.locale-it.js new file mode 100644 index 000000000..fec00456e --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-it.js @@ -0,0 +1 @@ +(function(a){a.jgrid={defaults:{recordtext:"Visualizzati {0} - {1} di {2}",emptyrecords:"Nessun record da visualizzare",loadtext:"Caricamento...",pgtext:"Pagina {0} di {1}"},search:{caption:"Ricerca...",Find:"Cerca",Reset:"Pulisci",odata:["uguale","diverso","minore","minore o uguale","maggiore","maggiore o uguale","inizia con","non inizia con","in","non in","termina con","non termina con","contiene","non contiene"],groupOps:[{op:"AND",text:"tutto"},{op:"OR",text:"almeno uno"}],matchText:" corrisponde",rulesText:" regole"},edit:{addCaption:"Aggiungi Record",editCaption:"Modifica Record",bSubmit:"Invia",bCancel:"Chiudi",bClose:"Chiudi",saveData:"Alcuni dati modificati! Salvare i cambiamenti?",bYes:"Si",bNo:"No",bExit:"Esci",msg:{required:"Campo richiesto",number:"Per favore, inserisci un valore valido",minValue:"il valore deve essere maggiore o uguale a ",maxValue:"il valore deve essere minore o uguale a",email:"e-mail non corretta",integer:"Per favore, inserisci un numero intero valido",date:"Per favore, inserisci una data valida",url:"URL non valido. Prefisso richiesto ('http://' or 'https://')",nodefined:" non definito!",novalue:" valore di ritorno richiesto!",customarray:"La function custon deve tornare un array!",customfcheck:"La function custom deve esistere per il custom checking!"}},view:{caption:"Visualizzazione Record",bClose:"Chiudi"},del:{caption:"Cancella",msg:"Cancellare record selezionato/i?",bSubmit:"Cancella",bCancel:"Annulla"},nav:{edittext:" ",edittitle:"Modifica record selezionato",addtext:" ",addtitle:"Aggiungi nuovo record",deltext:" ",deltitle:"Cancella record selezionato",searchtext:" ",searchtitle:"Ricerca record",refreshtext:"",refreshtitle:"Aggiorna griglia",alertcap:"Attenzione",alerttext:"Per favore, seleziona un record",viewtext:"",viewtitle:"Visualizza riga selezionata"},col:{caption:"Mostra/Nascondi Colonne",bSubmit:"Invia",bCancel:"Annulla"},errors:{errcap:"Errore",nourl:"Url non settata",norecords:"Nessun record da elaborare",model:"Lunghezza di colNames <> colModel!"},formatter:{integer:{thousandsSeparator:" ",defaultValue:"0"},number:{decimalSeparator:",",thousandsSeparator:" ",decimalPlaces:2,defaultValue:"0,00"},currency:{decimalSeparator:",",thousandsSeparator:" ",decimalPlaces:2,prefix:"",suffix:"",defaultValue:"0,00"},date:{dayNames:["Dom","Lun","Mar","Mer","Gio","Ven","Sab","Domenica","Luned","Marted","Mercoled","Gioved","Venerd","Sabato"],monthNames:["Gen","Feb","Mar","Apr","Mag","Gui","Lug","Ago","Set","Ott","Nov","Dic","Genneio","Febbraio","Marzo","Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Movembre","Dicembre"],AmPm:["am","pm","AM","PM"],S:function(b){return b<11||b>13?["st","nd","rd","th"][Math.min((b-1)%10,3)]:"th"},srcformat:"Y-m-d",newformat:"d/m/Y",masks:{ISO8601Long:"Y-m-d H:i:s",ISO8601Short:"Y-m-d",ShortDate:"n/j/Y",LongDate:"l, F d, Y",FullDateTime:"l, F d, Y g:i:s A",MonthDay:"F d",ShortTime:"g:i A",LongTime:"g:i:s A",SortableDateTime:"Y-m-d\\TH:i:s",UniversalSortableDateTime:"Y-m-d H:i:sO",YearMonth:"F, Y"},reformatAfterEdit:false},baseLinkUrl:"",showAction:"",target:"",checkbox:{disabled:true},idName:"id"}}})(jQuery);
\ No newline at end of file diff --git a/ishtar_common/static/js/i18n/grid.locale-ja.js b/ishtar_common/static/js/i18n/grid.locale-ja.js new file mode 100644 index 000000000..fd3b7371d --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-ja.js @@ -0,0 +1,155 @@ +;(function($){
+/**
+ * jqGrid Japanese Translation
+ * OKADA Yoshitada okada.dev@sth.jp
+ * http://trirand.com/blog/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "{2} \u4EF6\u4E2D {0} - {1} \u3092\u8868\u793A ",
+ emptyrecords: "\u8868\u793A\u3059\u308B\u30EC\u30B3\u30FC\u30C9\u304C\u3042\u308A\u307E\u305B\u3093",
+ loadtext: "\u8aad\u307f\u8fbc\u307f\u4e2d...",
+ pgtext : "{1} \u30DA\u30FC\u30B8\u4E2D {0} \u30DA\u30FC\u30B8\u76EE "
+ },
+ search : {
+ caption: "\u691c\u7d22...",
+ Find: "\u691c\u7d22",
+ Reset: "\u30ea\u30bb\u30c3\u30c8",
+ odata: ["\u6B21\u306B\u7B49\u3057\u3044", "\u6B21\u306B\u7B49\u3057\u304F\u306A\u3044",
+ "\u6B21\u3088\u308A\u5C0F\u3055\u3044", "\u6B21\u306B\u7B49\u3057\u3044\u304B\u5C0F\u3055\u3044",
+ "\u6B21\u3088\u308A\u5927\u304D\u3044", "\u6B21\u306B\u7B49\u3057\u3044\u304B\u5927\u304D\u3044",
+ "\u6B21\u3067\u59CB\u307E\u308B", "\u6B21\u3067\u59CB\u307E\u3089\u306A\u3044",
+ "\u6B21\u306B\u542B\u307E\u308C\u308B", "\u6B21\u306B\u542B\u307E\u308C\u306A\u3044",
+ "\u6B21\u3067\u7D42\u308F\u308B", "\u6B21\u3067\u7D42\u308F\u3089\u306A\u3044",
+ "\u6B21\u3092\u542B\u3080", "\u6B21\u3092\u542B\u307E\u306A\u3044"],
+ groupOps: [{
+ op: "AND",
+ text: "\u3059\u3079\u3066\u306E"
+ },
+ {
+ op: "OR",
+ text: "\u3044\u305A\u308C\u304B\u306E"
+ }],
+ matchText: " \u6B21\u306E",
+ rulesText: " \u6761\u4EF6\u3092\u6E80\u305F\u3059"
+ },
+ edit : {
+ addCaption: "\u30ec\u30b3\u30fc\u30c9\u8ffd\u52a0",
+ editCaption: "\u30ec\u30b3\u30fc\u30c9\u7de8\u96c6",
+ bSubmit: "\u9001\u4fe1",
+ bCancel: "\u30ad\u30e3\u30f3\u30bb\u30eb",
+ bClose: "\u9589\u3058\u308b",
+ saveData: "\u30C7\u30FC\u30BF\u304C\u5909\u66F4\u3055\u308C\u3066\u3044\u307E\u3059\u3002\u4FDD\u5B58\u3057\u307E\u3059\u304B\uFF1F",
+ bYes: "\u306F\u3044",
+ bNo: "\u3044\u3044\u3048",
+ bExit: "\u30AD\u30E3\u30F3\u30BB\u30EB",
+ msg: {
+ required:"\u3053\u306e\u9805\u76ee\u306f\u5fc5\u9808\u3067\u3059\u3002",
+ number:"\u6b63\u3057\u3044\u6570\u5024\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044\u3002",
+ minValue:"\u6b21\u306e\u5024\u4ee5\u4e0a\u3067\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044\u3002",
+ maxValue:"\u6b21\u306e\u5024\u4ee5\u4e0b\u3067\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044\u3002",
+ email: "e-mail\u304c\u6b63\u3057\u304f\u3042\u308a\u307e\u305b\u3093\u3002",
+ integer: "\u6b63\u3057\u3044\u6574\u6570\u5024\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044\u3002",
+ date: "\u6b63\u3057\u3044\u5024\u3092\u5165\u529b\u3057\u3066\u4e0b\u3055\u3044\u3002",
+ url: "\u306F\u6709\u52B9\u306AURL\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002\20\u30D7\u30EC\u30D5\u30A3\u30C3\u30AF\u30B9\u304C\u5FC5\u8981\u3067\u3059\u3002 ('http://' \u307E\u305F\u306F 'https://')",
+ nodefined: " \u304C\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u307E\u305B\u3093",
+ novalue: " \u623B\u308A\u5024\u304C\u5FC5\u8981\u3067\u3059",
+ customarray: "\u30AB\u30B9\u30BF\u30E0\u95A2\u6570\u306F\u914D\u5217\u3092\u8FD4\u3059\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059",
+ customfcheck: "\u30AB\u30B9\u30BF\u30E0\u691C\u8A3C\u306B\u306F\u30AB\u30B9\u30BF\u30E0\u95A2\u6570\u304C\u5FC5\u8981\u3067\u3059"
+ }
+ },
+ view : {
+ caption: "\u30EC\u30B3\u30FC\u30C9\u3092\u8868\u793A",
+ bClose: "\u9589\u3058\u308B"
+ },
+ del : {
+ caption: "\u524a\u9664",
+ msg: "\u9078\u629e\u3057\u305f\u30ec\u30b3\u30fc\u30c9\u3092\u524a\u9664\u3057\u307e\u3059\u304b\uff1f",
+ bSubmit: "\u524a\u9664",
+ bCancel: "\u30ad\u30e3\u30f3\u30bb\u30eb"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "\u9078\u629e\u3057\u305f\u884c\u3092\u7de8\u96c6",
+ addtext:" ",
+ addtitle: "\u884c\u3092\u65b0\u898f\u8ffd\u52a0",
+ deltext: " ",
+ deltitle: "\u9078\u629e\u3057\u305f\u884c\u3092\u524a\u9664",
+ searchtext: " ",
+ searchtitle: "\u30ec\u30b3\u30fc\u30c9\u691c\u7d22",
+ refreshtext: "",
+ refreshtitle: "\u30b0\u30ea\u30c3\u30c9\u3092\u30ea\u30ed\u30fc\u30c9",
+ alertcap: "\u8b66\u544a",
+ alerttext: "\u884c\u3092\u9078\u629e\u3057\u3066\u4e0b\u3055\u3044\u3002",
+ viewtext: "",
+ viewtitle: "\u9078\u629E\u3057\u305F\u884C\u3092\u8868\u793A"
+ },
+ col : {
+ caption: "\u5217\u3092\u8868\u793a\uff0f\u96a0\u3059",
+ bSubmit: "\u9001\u4fe1",
+ bCancel: "\u30ad\u30e3\u30f3\u30bb\u30eb"
+ },
+ errors : {
+ errcap : "\u30a8\u30e9\u30fc",
+ nourl : "URL\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002",
+ norecords: "\u51e6\u7406\u5bfe\u8c61\u306e\u30ec\u30b3\u30fc\u30c9\u304c\u3042\u308a\u307e\u305b\u3093\u3002",
+ model : "colNames\u306e\u9577\u3055\u304ccolModel\u3068\u4e00\u81f4\u3057\u307e\u305b\u3093\u3002"
+ },
+ formatter : {
+ integer: {
+ thousandsSeparator: ",",
+ defaultValue: '0'
+ },
+ number: {
+ decimalSeparator: ".",
+ thousandsSeparator: ",",
+ decimalPlaces: 2,
+ defaultValue: '0.00'
+ },
+ currency: {
+ decimalSeparator: ".",
+ thousandsSeparator: ",",
+ decimalPlaces: 0,
+ prefix: "",
+ suffix: "",
+ defaultValue: '0'
+ },
+ date : {
+ dayNames: [
+ "\u65e5", "\u6708", "\u706b", "\u6c34", "\u6728", "\u91d1", "\u571f",
+ "\u65e5", "\u6708", "\u706b", "\u6c34", "\u6728", "\u91d1", "\u571f"
+ ],
+ monthNames: [
+ "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12",
+ "1\u6708", "2\u6708", "3\u6708", "4\u6708", "5\u6708", "6\u6708", "7\u6708", "8\u6708", "9\u6708", "10\u6708", "11\u6708", "12\u6708"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: "\u756a\u76ee",
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-nl.js b/ishtar_common/static/js/i18n/grid.locale-nl.js new file mode 100644 index 000000000..093d1eec0 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-nl.js @@ -0,0 +1,149 @@ +(function(a) {
+ a.jgrid =
+ {
+ defaults:
+ {
+ recordtext: "regels {0} - {1} van {2}",
+ emptyrecords: "Geen data gevonden.",
+ loadtext: "laden...",
+ pgtext: "pagina {0} van {1}"
+ },
+ search:
+ {
+ caption: "Zoeken...",
+ Find: "Zoek",
+ Reset: "Herstellen",
+ odata: ["gelijk aan", "niet gelijk aan", "kleiner dan", "kleiner dan of gelijk aan", "groter dan", "groter dan of gelijk aan", "begint met", "begint niet met", "is in", "is niet in", "eindigd met", "eindigd niet met", "bevat", "bevat niet"],
+ groupOps: [{ op: "AND", text: "alle" }, { op: "OR", text: "een van de"}],
+ matchText: " match",
+ rulesText: " regels"
+ },
+ edit:
+ {
+ addCaption: "Nieuw",
+ editCaption: "Bewerken",
+ bSubmit: "Opslaan",
+ bCancel: "Annuleren",
+ bClose: "Sluiten",
+ saveData: "Er is data aangepast! Wijzigingen opslaan?",
+ bYes: "Ja",
+ bNo: "Nee",
+ bExit: "Sluiten",
+ msg:
+ {
+ required: "Veld is verplicht",
+ number: "Voer a.u.b. geldig nummer in",
+ minValue: "Waarde moet groter of gelijk zijn aan ",
+ maxValue: "Waarde moet kleiner of gelijks zijn aan",
+ email: "is geen geldig e-mailadres",
+ integer: "Voer a.u.b. een geldig getal in",
+ date: "Voer a.u.b. een geldige waarde in",
+ url: "is geen geldige URL. Prefix is verplicht ('http://' or 'https://')",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+ }
+ },
+ view:
+ {
+ caption: "Tonen",
+ bClose: "Sluiten"
+ },
+ del:
+ {
+ caption: "Verwijderen",
+ msg: "Verwijder geselecteerde regel(s)?",
+ bSubmit: "Verwijderen",
+ bCancel: "Annuleren"
+ },
+ nav:
+ {
+ edittext: "",
+ edittitle: "Bewerken",
+ addtext: "",
+ addtitle: "Nieuw",
+ deltext: "",
+ deltitle: "Verwijderen",
+ searchtext: "",
+ searchtitle: "Zoeken",
+ refreshtext: "",
+ refreshtitle: "Vernieuwen",
+ alertcap: "Waarschuwing",
+ alerttext: "Selecteer a.u.b. een regel",
+ viewtext: "",
+ viewtitle: "Openen"
+ },
+ col:
+ {
+ caption: "Tonen/verbergen kolommen",
+ bSubmit: "OK",
+ bCancel: "Annuleren"
+ },
+ errors:
+ {
+ errcap: "Fout",
+ nourl: "Er is geen URL gedefinieerd",
+ norecords: "Geen data om te verwerken",
+ model: "Lengte van 'colNames' is niet gelijk aan 'colModel'!"
+ },
+ formatter:
+ {
+ integer:
+ {
+ thousandsSeparator: ".",
+ defaultValue: "0"
+ },
+ number:
+ {
+ decimalSeparator: ",",
+ thousandsSeparator: ".",
+ decimalPlaces: 2,
+ defaultValue: "0.00"
+ },
+ currency:
+ {
+ decimalSeparator: ",",
+ thousandsSeparator: ".",
+ decimalPlaces: 2,
+ prefix: "EUR ",
+ suffix: "",
+ defaultValue: "0.00"
+ },
+ date:
+ {
+ dayNames: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag"],
+ monthNames: ["Jan", "Feb", "Maa", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Januari", "Februari", "Maart", "April", "Mei", "Juni", "Juli", "Augustus", "September", "October", "November", "December"],
+ AmPm: ["am", "pm", "AM", "PM"],
+ S: function(b) {
+ return b < 11 || b > 13 ? ["st", "nd", "rd", "th"][Math.min((b - 1) % 10, 3)] : "th"
+ },
+ srcformat: "Y-m-d",
+ newformat: "d/m/Y",
+ masks:
+ {
+ ISO8601Long: "Y-m-d H:i:s",
+ ISO8601Short: "Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l d F Y G:i:s",
+ MonthDay: "d F",
+ ShortTime: "G:i",
+ LongTime: "G:i:s",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit: false
+ },
+ baseLinkUrl: "",
+ showAction: "",
+ target: "",
+ checkbox:
+ {
+ disabled: true
+ },
+ idName: "id"
+ }
+ }
+})(jQuery);
\ No newline at end of file diff --git a/ishtar_common/static/js/i18n/grid.locale-no.js b/ishtar_common/static/js/i18n/grid.locale-no.js new file mode 100644 index 000000000..a70ef6d79 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-no.js @@ -0,0 +1 @@ +(function(a){a.jgrid={};a.jgrid.defaults={recordtext:"Rad {0} - {1}, totalt {2}",loadtext:"Laster...",pgtext:"Side {0} av {1}"};a.jgrid.search={caption:"Sk...",Find:"Finn",Reset:"Nullstill",odata:["lik","forskjellig fra","mindre enn","mindre eller lik","strre enn"," strre eller lik","starter med","slutter med","inneholder"]};a.jgrid.edit={addCaption:"Ny rad",editCaption:"Rediger",bSubmit:"Send",bCancel:"Avbryt",bClose:"Lukk",processData:"Laster...",msg:{required:"Felt er obligatorisk",number:"Legg inn et gyldig tall",minValue:"verdi m vre strre enn eller lik",maxValue:"verdi m vre mindre enn eller lik",email:"er ikke en gyldig e-post adresse",integer:"Legg inn et gyldig heltall",date:"Legg inn en gyldig dato",url:"er ikke en gyldig URL. Prefiks pkrevd ('http://' eller 'https://')",nodefined:" er ikke definert!",novalue:" returverdi er pkrevd!",customarray:"Tilpasset funksjon m returnere en tabell!",customfcheck:"Tilpasset funksjon m eksistere!"}};a.jgrid.view={caption:"pne post",bClose:"Lukk"};a.jgrid.del={caption:"Slett",msg:"Slett valgte rad(er)?",bSubmit:"Slett",bCancel:"Avbryt",processData:"Behandler..."};a.jgrid.nav={edittext:" ",edittitle:"Rediger valgte rad(er)",addtext:" ",addtitle:"Legg til ny rad",deltext:" ",deltitle:"Slett valgte rad(er)",searchtext:" ",searchtitle:"Sk",refreshtext:"",refreshtitle:"Oppdater tabell",alertcap:"Advarsel",alerttext:"Velg rad",viewtext:" ",viewtitle:"pne valgt rad"};a.jgrid.col={caption:"Vis/skjul kolonner",bSubmit:"Utfr",bCancel:"Avbryt"};a.jgrid.errors={errcap:"Feil",nourl:"Ingen url er satt",norecords:"Ingen poster behandle",model:"colNames og colModel har forskjellig lengde!"};a.jgrid.formatter={integer:{thousandsSeparator:" ",defaulValue:0},number:{decimalSeparator:",",thousandsSeparator:" ",decimalPlaces:2,defaulValue:0},currency:{decimalSeparator:",",thousandsSeparator:" ",decimalPlaces:2,prefix:"",suffix:"",defaulValue:0},date:{dayNames:["s.","ma.","ti.","on.","to.","fr.","l.","Sndag","Mandag","Tirsdag","Onsdag","Torsdag","Fredag","Lrdag"],monthNames:["jan.","feb.","mars","april","mai","juni","juli","aug.","sep.","okt.","nov.","des.","januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember"],AmPm:["","","",""],S:function(b){return"."},srcformat:"Y-m-d H:i:s",newformat:"Y-m-d H:i:s",masks:{ISO8601Long:"Y-m-d H:i:s",ISO8601Short:"Y-m-d",ShortDate:"j.n.Y",LongDate:"l j. F Y",FullDateTime:"l j. F Y kl. G.i.s",MonthDay:"j. F",ShortTime:"H:i",LongTime:"H:i:s",SortableDateTime:"Y-m-d\\TH:i:s",UniversalSortableDateTime:"Y-m-d H:i:sO",YearMonth:"F Y"},reformatAfterEdit:false},baseLinkUrl:"",showAction:"show",addParam:"",checkbox:{disabled:true}}})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-pl.js b/ishtar_common/static/js/i18n/grid.locale-pl.js new file mode 100644 index 000000000..3e3f17855 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-pl.js @@ -0,0 +1,127 @@ +;(function($){
+/**
+ * jqGrid Polish Translation
+ * Łukasz Schab
+ * http://FreeTree.pl
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Pokaż {0} - {1} z {2}",
+ emptyrecords: "Brak rekordów do pokazania",
+ loadtext: "\u0142adowanie...",
+ pgtext : "Strona {0} z {1}"
+ },
+ search : {
+ caption: "Wyszukiwanie...",
+ Find: "Szukaj",
+ Reset: "Czyść",
+ odata : ['dok\u0142adnie', 'różne od', 'mniejsze od', 'mniejsze lub równe','większe od','większe lub równe', 'zaczyna się od','nie zaczyna się od','zawiera','nie zawiera','kończy się na','nie kończy się na','zawiera','nie zawiera'],
+ groupOps: [ { op: "ORAZ", text: "wszystkie" }, { op: "LUB", text: "każdy" } ],
+ matchText: " pasuje",
+ rulesText: " regu\u0142y"
+ },
+ edit : {
+ addCaption: "Dodaj rekord",
+ editCaption: "Edytuj rekord",
+ bSubmit: "Zapisz",
+ bCancel: "Anuluj",
+ bClose: "Zamknij",
+ saveData: "Dane zosta\u0142y zmienione! Zapisać zmiany?",
+ bYes : "Tak",
+ bNo : "Nie",
+ bExit : "Anuluj",
+ msg: {
+ required:"Pole jest wymagane",
+ number:"Proszę wpisać poprawną liczbę",
+ minValue:"wartość musi być większa lub równa",
+ maxValue:"wartość musi być mniejsza od",
+ email: "nie jest adresem e-mail",
+ integer: "Proszę wpisać poprawną liczbę",
+ date: "Proszę podaj poprawną datę",
+ url: "jest niew\u0142aściwym adresem URL. Pamiętaj o prefiksie ('http://' lub 'https://')",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+ }
+ },
+ view : {
+ caption: "Pokaż rekord",
+ bClose: "Zamknij"
+ },
+ del : {
+ caption: "Usuwanie",
+ msg: "Czy usunąć wybrany rekord(y)?",
+ bSubmit: "Usuń",
+ bCancel: "Anuluj"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Edytuj wybrany wiersz",
+ addtext:" ",
+ addtitle: "Dodaj nowy wiersz",
+ deltext: " ",
+ deltitle: "Usuń wybrany wiersz",
+ searchtext: " ",
+ searchtitle: "Wyszukaj rekord",
+ refreshtext: "",
+ refreshtitle: "Prze\u0142aduj",
+ alertcap: "Uwaga",
+ alerttext: "Proszę wybrać wiersz",
+ viewtext: "",
+ viewtitle: "View selected row"
+ },
+ col : {
+ caption: "Pokaż/Ukryj kolumny",
+ bSubmit: "Zatwierdź",
+ bCancel: "Anuluj"
+ },
+ errors : {
+ errcap : "B\u0142ąd",
+ nourl : "Brak adresu url",
+ norecords: "Brak danych",
+ model : "D\u0142ugość colNames <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "Nie", "Pon", "Wt", "Śr", "Cz", "Pi", "So",
+ "Niedziela", "Poniedzia\u0142ek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota"
+ ],
+ monthNames: [
+ "Sty", "Lu", "Mar", "Kwie", "Maj", "Cze", "Lip", "Sie", "Wrz", "Paź", "Lis", "Gru",
+ "Styczeń", "Luty", "Marzec", "Kwiecień", "Maj", "Czerwiec", "Lipiec", "Sierpień", "Wrzesień", "Październik", "Listopad", "Grudzień"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['', '', '', ''][Math.min((j - 1) % 10, 3)] : ''},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
\ No newline at end of file diff --git a/ishtar_common/static/js/i18n/grid.locale-pt-br.js b/ishtar_common/static/js/i18n/grid.locale-pt-br.js new file mode 100644 index 000000000..ae01258c5 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-pt-br.js @@ -0,0 +1,127 @@ +;(function($){
+/**
+ * jqGrid Brazilian-Portuguese Translation
+ * Sergio Righi sergio.righi@gmail.com
+ * http://curve.com.br
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Ver {0} - {1} of {2}",
+ emptyrecords: "Nenhum registro para visualizar",
+ loadtext: "Carregando...",
+ pgtext : "Página {0} de {1}"
+ },
+ search : {
+ caption: "Procurar...",
+ Find: "Procurar",
+ Reset: "Resetar",
+ odata : ['equal', 'not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is in','is not in','ends with','does not end with','contains','does not contain'],
+ groupOps: [ { op: "AND", text: "all" }, { op: "OR", text: "any" } ],
+ matchText: " iguala",
+ rulesText: " regras"
+ },
+ edit : {
+ addCaption: "Incluir",
+ editCaption: "Alterar",
+ bSubmit: "Enviar",
+ bCancel: "Cancelar",
+ bClose: "Fechar",
+ saveData: "Os dados foram alterados! Salvar alterações?",
+ bYes : "Sim",
+ bNo : "Não",
+ bExit : "Cancelar",
+ msg: {
+ required:"Campo obrigatório",
+ number:"Por favor, informe um número válido",
+ minValue:"valor deve ser igual ou maior que ",
+ maxValue:"valor deve ser menor ou igual a",
+ email: "este e-mail não é válido",
+ integer: "Por favor, informe um valor inteiro",
+ date: "Por favor, informe uma data válida",
+ url: "não é uma URL válida. Prefixo obrigatório ('http://' or 'https://')",
+ nodefined : " não está definido!",
+ novalue : " um valor de retorno é obrigatório!",
+ customarray : "Função customizada deve retornar um array!",
+ customfcheck : "Função customizada deve estar presente em caso de validação customizada!"
+ }
+ },
+ view : {
+ caption: "Ver Registro",
+ bClose: "Fechar"
+ },
+ del : {
+ caption: "Apagar",
+ msg: "Apagar registros selecionado(s)?",
+ bSubmit: "Apagar",
+ bCancel: "Cancelar"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Alterar registro selecionado",
+ addtext:" ",
+ addtitle: "Incluir novo registro",
+ deltext: " ",
+ deltitle: "Apagar registro selecionado",
+ searchtext: " ",
+ searchtitle: "Procurar registros",
+ refreshtext: "",
+ refreshtitle: "Recarrgando Tabela",
+ alertcap: "Aviso",
+ alerttext: "Por favor, selecione um registro",
+ viewtext: "",
+ viewtitle: "Ver linha selecionada"
+ },
+ col : {
+ caption: "Mostrar/Esconder Colunas",
+ bSubmit: "Enviar",
+ bCancel: "Cancelar"
+ },
+ errors : {
+ errcap : "Erro",
+ nourl : "Nenhuma URL defenida",
+ norecords: "Sem registros para exibir",
+ model : "Comprimento de colNames <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0,00'},
+ currency : {decimalSeparator:",", thousandsSeparator: ".", decimalPlaces: 2, prefix: "R$ ", suffix:"", defaultValue: '0,00'},
+ date : {
+ dayNames: [
+ "Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sáb",
+ "Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"
+ ],
+ monthNames: [
+ "Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez",
+ "Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['º', 'º', 'º', 'º'][Math.min((j - 1) % 10, 3)] : 'º'},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-pt.js b/ishtar_common/static/js/i18n/grid.locale-pt.js new file mode 100644 index 000000000..737219db3 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-pt.js @@ -0,0 +1,125 @@ +;(function($){
+/**
+ * jqGrid Portuguese Translation
+* Traduo da jqGrid em Portugues por Frederico Carvalho, http://www.eyeviewdesign.pt
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "View {0} - {1} of {2}",
+ emptyrecords: "No records to view",
+ loadtext: "A carregar...",
+ pgtext : "Page {0} of {1}"
+ },
+ search : {
+ caption: "Busca...",
+ Find: "Procurar",
+ Reset: "Limpar",
+ odata : ['equal', 'not equal', 'less', 'less or equal','greater','greater or equal', 'begins with','does not begin with','is in','is not in','ends with','does not end with','contains','does not contain'],
+ groupOps: [ { op: "AND", text: "all" }, { op: "OR", text: "any" } ],
+ matchText: " match",
+ rulesText: " rules"
+ },
+ edit : {
+ addCaption: "Adicionar Registo",
+ editCaption: "Modificar Registo",
+ bSubmit: "Submeter",
+ bCancel: "Cancelar",
+ bClose: "Fechar",
+ saveData: "Data has been changed! Save changes?",
+ bYes : "Yes",
+ bNo : "No",
+ bExit : "Cancel",
+ msg: {
+ required:"Campo obrigatrio",
+ number:"Por favor, introduza um numero",
+ minValue:"O valor deve ser maior ou igual que",
+ maxValue:"O valor deve ser menor ou igual a",
+ email: "No um endereo de email vlido",
+ integer: "Por favor, introduza um numero inteiro",
+ url: "is not a valid URL. Prefix required ('http://' or 'https://')",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+ }
+ },
+ view : {
+ caption: "View Record",
+ bClose: "Close"
+ },
+ del : {
+ caption: "Eliminar",
+ msg: "Deseja eliminar o(s) registo(s) seleccionado(s)?",
+ bSubmit: "Eliminar",
+ bCancel: "Cancelar"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Modificar registo seleccionado",
+ addtext:" ",
+ addtitle: "Adicionar novo registo",
+ deltext: " ",
+ deltitle: "Eliminar registo seleccionado",
+ searchtext: " ",
+ searchtitle: "Procurar",
+ refreshtext: "",
+ refreshtitle: "Actualizar",
+ alertcap: "Aviso",
+ alerttext: "Por favor, seleccione um registo",
+ viewtext: "",
+ viewtitle: "View selected row"
+ },
+ col : {
+ caption: "Mostrar/Ocultar Colunas",
+ bSubmit: "Enviar",
+ bCancel: "Cancelar"
+ },
+ errors : {
+ errcap : "Erro",
+ nourl : "No especificou um url",
+ norecords: "No existem dados para processar",
+ model : "Tamanho do colNames <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sab",
+ "Domingo", "Segunda-Feira", "Tera-Feira", "Quarta-Feira", "Quinta-Feira", "Sexta-Feira", "Sbado"
+ ],
+ monthNames: [
+ "Jan", "Fev", "Mar", "Abr", "Mai", "Jun", "Jul", "Ago", "Set", "Out", "Nov", "Dez",
+ "Janeiro", "Fevereiro", "Maro", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['', '', '', ''][Math.min((j - 1) % 10, 3)] : ''},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-ro.js b/ishtar_common/static/js/i18n/grid.locale-ro.js new file mode 100644 index 000000000..d8513aff1 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-ro.js @@ -0,0 +1,139 @@ +;(function($){
+/**
+ * jqGrid Romanian Translation
+ * Alexandru Emil Lupu contact@alecslupu.ro
+ * http://www.alecslupu.ro/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Vizualizare {0} - {1} din {2}",
+ emptyrecords: "Nu există înregistrări de vizualizat",
+ loadtext: "Încărcare...",
+ pgtext : "Pagina {0} din {1}"
+ },
+ search : {
+ caption: "Caută...",
+ Find: "Caută",
+ Reset: "Resetare",
+ odata : ['egal', 'diferit', 'mai mic', 'mai mic sau egal','mai mare','mai mare sau egal', 'începe cu','nu începe cu','se găsește în','nu se găsește în','se termină cu','nu se termină cu','conține',''],
+ groupOps: [ { op: "AND", text: "toate" }, { op: "OR", text: "oricare" } ],
+ matchText: " găsite",
+ rulesText: " reguli"
+ },
+ edit : {
+ addCaption: "Adăugare înregistrare",
+ editCaption: "Modificare înregistrare",
+ bSubmit: "Salvează",
+ bCancel: "Anulare",
+ bClose: "Închide",
+ saveData: "Informațiile au fost modificate! Salvați modificările?",
+ bYes : "Da",
+ bNo : "Nu",
+ bExit : "Anulare",
+ msg: {
+ required:"Câmpul este obligatoriu",
+ number:"Vă rugăm introduceți un număr valid",
+ minValue:"valoarea trebuie sa fie mai mare sau egală cu",
+ maxValue:"valoarea trebuie sa fie mai mică sau egală cu",
+ email: "nu este o adresă de e-mail validă",
+ integer: "Vă rugăm introduceți un număr valid",
+ date: "Vă rugăm să introduceți o dată validă",
+ url: "Nu este un URL valid. Prefixul este necesar('http://' or 'https://')",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+ }
+ },
+ view : {
+ caption: "Vizualizare înregistrare",
+ bClose: "Închidere"
+ },
+ del : {
+ caption: "Ștegere",
+ msg: "Ștergeți înregistrarea (înregistrările) selectate?",
+ bSubmit: "Șterge",
+ bCancel: "Anulare"
+ },
+ nav : {
+ edittext: "",
+ edittitle: "Modifică rândul selectat",
+ addtext:"",
+ addtitle: "Adaugă rând nou",
+ deltext: "",
+ deltitle: "Șterge rândul selectat",
+ searchtext: "",
+ searchtitle: "Căutare înregistrări",
+ refreshtext: "",
+ refreshtitle: "Reîncarcare Grid",
+ alertcap: "Avertisment",
+ alerttext: "Vă rugăm să selectați un rând",
+ viewtext: "",
+ viewtitle: "Vizualizează rândul selectat"
+ },
+ col : {
+ caption: "Arată/Ascunde coloanele",
+ bSubmit: "Salvează",
+ bCancel: "Anulare"
+ },
+ errors : {
+ errcap : "Eroare",
+ nourl : "Niciun url nu este setat",
+ norecords: "Nu sunt înregistrări de procesat",
+ model : "Lungimea colNames <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0,00'},
+ currency : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0,00'},
+ date : {
+ dayNames: [
+ "Dum", "Lun", "Mar", "Mie", "Joi", "Vin", "Sâm",
+ "Duminică", "Luni", "Marți", "Miercuri", "Joi", "Vineri", "Sâmbătă"
+ ],
+ monthNames: [
+ "Ian", "Feb", "Mar", "Apr", "Mai", "Iun", "Iul", "Aug", "Sep", "Oct", "Noi", "Dec",
+ "Ianuarie", "Februarie", "Martie", "Aprilie", "Mai", "Iunie", "Iulie", "August", "Septembrie", "Octombrie", "Noiembrie", "Decembrie"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ /*
+ Here is a problem in romanian:
+ M / F
+ 1st = primul / prima
+ 2nd = Al doilea / A doua
+ 3rd = Al treilea / A treia
+ 4th = Al patrulea/ A patra
+ 5th = Al cincilea / A cincea
+ 6th = Al șaselea / A șasea
+ 7th = Al șaptelea / A șaptea
+ ....
+ */
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-ru.js b/ishtar_common/static/js/i18n/grid.locale-ru.js new file mode 100644 index 000000000..910b0d764 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-ru.js @@ -0,0 +1,127 @@ +;(function($){
+/**
+ * jqGrid Russian Translation v1.0 02.07.2009 (based on translation by Alexey Kanaev v1.1 21.01.2009, http://softcore.com.ru)
+ * Sergey Dyagovchenko
+ * http://d.sumy.ua
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Просмотр {0} - {1} из {2}",
+ emptyrecords: "Нет записей для просмотра",
+ loadtext: "Загрузка...",
+ pgtext : "Стр. {0} из {1}"
+ },
+ search : {
+ caption: "Поиск...",
+ Find: "Найти",
+ Reset: "Сброс",
+ odata : ['равно', 'не равно', 'меньше', 'меньше или равно','больше','больше или равно', 'начинается с','не начинается с','находится в','не находится в','заканчивается на','не заканчивается на','содержит','не содержит'],
+ groupOps: [ { op: "AND", text: "все" }, { op: "OR", text: "любой" } ],
+ matchText: " совпадает",
+ rulesText: " правила"
+ },
+ edit : {
+ addCaption: "Добавить запись",
+ editCaption: "Редактировать запись",
+ bSubmit: "Сохранить",
+ bCancel: "Отмена",
+ bClose: "Закрыть",
+ saveData: "Данные были измененны! Сохранить изменения?",
+ bYes : "Да",
+ bNo : "Нет",
+ bExit : "Отмена",
+ msg: {
+ required:"Поле является обязательным",
+ number:"Пожалуйста, введите правильное число",
+ minValue:"значение должно быть больше либо равно",
+ maxValue:"значение должно быть меньше либо равно",
+ email: "некорректное значение e-mail",
+ integer: "Пожалуйста, введите целое число",
+ date: "Пожалуйста, введите правильную дату",
+ url: "неверная ссылка. Необходимо ввести префикс ('http://' or 'https://')",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+ }
+ },
+ view : {
+ caption: "Просмотр записи",
+ bClose: "Закрыть"
+ },
+ del : {
+ caption: "Удалить",
+ msg: "Удалить выбранную запись(и)?",
+ bSubmit: "Удалить",
+ bCancel: "Отмена"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Редактировать выбранную запись",
+ addtext:" ",
+ addtitle: "Добавить новую запись",
+ deltext: " ",
+ deltitle: "Удалить выбранную запись",
+ searchtext: " ",
+ searchtitle: "Найти записи",
+ refreshtext: "",
+ refreshtitle: "Обновить таблицу",
+ alertcap: "Внимание",
+ alerttext: "Пожалуйста, выберите запись",
+ viewtext: "",
+ viewtitle: "Просмотреть выбранную запись"
+ },
+ col : {
+ caption: "Показать/скрыть столбцы",
+ bSubmit: "Сохранить",
+ bCancel: "Отмена"
+ },
+ errors : {
+ errcap : "Ошибка",
+ nourl : "URL не установлен",
+ norecords: "Нет записей для обработки",
+ model : "Число полей не соответствует числу столбцов таблицы!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0,00'},
+ currency : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0,00'},
+ date : {
+ dayNames: [
+ "Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб",
+ "Воскресение", "Понедельник", "Вторник", "Среда", "Четверг", "Пятница", "Суббота"
+ ],
+ monthNames: [
+ "Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек",
+ "Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'd.m.Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n.j.Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y G:i:s",
+ MonthDay: "F d",
+ ShortTime: "G:i",
+ LongTime: "G:i:s",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-sk.js b/ishtar_common/static/js/i18n/grid.locale-sk.js new file mode 100644 index 000000000..f08437f74 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-sk.js @@ -0,0 +1,127 @@ +;(function($){
+/**
+ * jqGrid Slovak Translation
+ * Milan Cibulka
+ * http://trirand.com/blog/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Zobrazených {0} - {1} z {2} záznamov",
+ emptyrecords: "Neboli nájdené žiadne záznamy",
+ loadtext: "Načítám...",
+ pgtext : "Strana {0} z {1}"
+ },
+ search : {
+ caption: "Vyhľadávam...",
+ Find: "Hľadať",
+ Reset: "Reset",
+ odata : ['rovná sa', 'nerovná sa', 'menšie', 'menšie alebo rovnajúce sa','väčšie', 'väčšie alebo rovnajúce sa', 'začína s', 'nezačína s', 'je v', 'nie je v', 'končí s', 'nekončí s', 'obahuje', 'neobsahuje'],
+ groupOps: [ { op: "AND", text: "všetkých" }, { op: "OR", text: "niektorého z" } ],
+ matchText: " hľadať podla",
+ rulesText: " pravidiel"
+ },
+ edit : {
+ addCaption: "Pridať záznam",
+ editCaption: "Editácia záznamov",
+ bSubmit: "Uložiť",
+ bCancel: "Storno",
+ bClose: "Zavrieť",
+ saveData: "Údaje boli zmenené! Uložiť zmeny?",
+ bYes : "Ano",
+ bNo : "Nie",
+ bExit : "Zrušiť",
+ msg: {
+ required:"Pole je požadované",
+ number:"Prosím, vložte valídne číslo",
+ minValue:"hodnota musí býť väčšia ako alebo rovná ",
+ maxValue:"hodnota musí býť menšia ako alebo rovná ",
+ email: "nie je valídny e-mail",
+ integer: "Prosím, vložte celé číslo",
+ date: "Prosím, vložte valídny dátum",
+ url: "nie je platnou URL. Požadovaný prefix ('http://' alebo 'https://')",
+ nodefined : " nie je definovaný!",
+ novalue : " je vyžadovaná návratová hodnota!",
+ customarray : "Custom function mala vrátiť pole!",
+ customfcheck : "Custom function by mala byť prítomná v prípade custom checking!"
+ }
+ },
+ view : {
+ caption: "Zobraziť záznam",
+ bClose: "Zavrieť"
+ },
+ del : {
+ caption: "Zmazať",
+ msg: "Zmazať vybraný(é) záznam(y)?",
+ bSubmit: "Zmazať",
+ bCancel: "Storno"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Editovať vybraný riadok",
+ addtext:" ",
+ addtitle: "Pridať nový riadek",
+ deltext: " ",
+ deltitle: "Zmazať vybraný záznam ",
+ searchtext: " ",
+ searchtitle: "Nájsť záznamy",
+ refreshtext: "",
+ refreshtitle: "Obnoviť tabuľku",
+ alertcap: "Varovanie",
+ alerttext: "Prosím, vyberte riadok",
+ viewtext: "",
+ viewtitle: "Zobraziť vybraný riadok"
+ },
+ col : {
+ caption: "Zobrazit/Skrýť stĺpce",
+ bSubmit: "Uložiť",
+ bCancel: "Storno"
+ },
+ errors : {
+ errcap : "Chyba",
+ nourl : "Nie je nastavená url",
+ norecords: "Žiadne záznamy k spracovaniu",
+ model : "Dĺžka colNames <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "Ne", "Po", "Ut", "St", "Št", "Pi", "So",
+ "Nedela", "Pondelok", "Utorok", "Streda", "Štvrtok", "Piatek", "Sobota"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Mar", "Apr", "Máj", "Jún", "Júl", "Aug", "Sep", "Okt", "Nov", "Dec",
+ "Január", "Február", "Marec", "Apríl", "Máj", "Jún", "Júl", "August", "September", "Október", "November", "December"
+ ],
+ AmPm : ["do","od","DO","OD"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-sr.js b/ishtar_common/static/js/i18n/grid.locale-sr.js new file mode 100644 index 000000000..305b17e2b --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-sr.js @@ -0,0 +1,128 @@ +;(function($){
+/**
+ * jqGrid Serbian Translation
+ * Александар Миловац(Aleksandar Milovac) aleksandar.milovac@gmail.com
+ * http://trirand.com/blog/
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Преглед {0} - {1} од {2}",
+ emptyrecords: "Не постоји ниједан запис",
+ loadtext: "Учитавање...",
+ pgtext : "Страна {0} од {1}"
+ },
+ search : {
+ caption: "Тражење...",
+ Find: "Тражи",
+ Reset: "Ресетуј",
+ odata : ['једнако', 'није једнако', 'мање', 'мање или једнако','веће','веће или једнако', 'почиње са','не почиње са','је у','није у','завршава са','не завршава са','садржи','не садржи'],
+ groupOps: [ { op: "И", text: "сви" }, { op: "ИЛИ", text: "сваки" } ],
+ matchText: " match",
+ rulesText: " правила"
+ },
+ edit : {
+ addCaption: "Додај запис",
+ editCaption: "Измени запис",
+ bSubmit: "Пошаљи",
+ bCancel: "Одустани",
+ bClose: "Затвори",
+ saveData: "Податак је измењен! Сачувај измене?",
+ bYes : "Да",
+ bNo : "Не",
+ bExit : "Одустани",
+ msg: {
+ required:"Поље је обавезно",
+ number:"Молим, унесите исправан број",
+ minValue:"вредност мора бити већа од или једнака са ",
+ maxValue:"вредност мора бити мања од или једнака са",
+ email: "није исправна имејл адреса",
+ integer: "Молим, унесите исправну целобројну вредност ",
+ date: "Молим, унесите исправан датум",
+ url: "није исправан УРЛ. Потребан је префикс ('http://' or 'https://')",
+ nodefined : " није дефинисан!",
+ novalue : " захтевана је повратна вредност!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+
+ }
+ },
+ view : {
+ caption: "Погледај запис",
+ bClose: "Затвори"
+ },
+ del : {
+ caption: "Избриши",
+ msg: "Избриши изабран(е) запис(е)?",
+ bSubmit: "Ибриши",
+ bCancel: "Одбаци"
+ },
+ nav : {
+ edittext: "",
+ edittitle: "Измени изабрани ред",
+ addtext:"",
+ addtitle: "Додај нови ред",
+ deltext: "",
+ deltitle: "Избриши изабран ред",
+ searchtext: "",
+ searchtitle: "Нађи записе",
+ refreshtext: "",
+ refreshtitle: "Поново учитај податке",
+ alertcap: "Упозорење",
+ alerttext: "Молим, изаберите ред",
+ viewtext: "",
+ viewtitle: "Погледај изабрани ред"
+ },
+ col : {
+ caption: "Изабери колоне",
+ bSubmit: "ОК",
+ bCancel: "Одбаци"
+ },
+ errors : {
+ errcap : "Грешка",
+ nourl : "Није постављен URL",
+ norecords: "Нема записа за обраду",
+ model : "Дужина модела colNames <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "Нед", "Пон", "Уто", "Сре", "Чет", "Пет", "Суб",
+ "Недеља", "Понедељак", "Уторак", "Среда", "Четвртак", "Петак", "Субота"
+ ],
+ monthNames: [
+ "Јан", "Феб", "Мар", "Апр", "Мај", "Јун", "Јул", "Авг", "Сеп", "Окт", "Нов", "Дец",
+ "Јануар", "Фебруар", "Март", "Април", "Мај", "Јун", "Јул", "Август", "Септембар", "Октобар", "Новембар", "Децембар"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-sv.js b/ishtar_common/static/js/i18n/grid.locale-sv.js new file mode 100644 index 000000000..fd28e6b87 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-sv.js @@ -0,0 +1,127 @@ +;(function($){
+/**
+ * jqGrid Swedish Translation
+ * Harald Normann harald.normann@wts.se, harald.normann@gmail.com
+ * http://www.worldteamsoftware.com
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Visar {0} - {1} av {2}",
+ emptyrecords: "Det finns inga poster att visa",
+ loadtext: "Laddar...",
+ pgtext : "Sida {0} av {1}"
+ },
+ search : {
+ caption: "Sök Poster - Ange sökvillkor",
+ Find: "Sök",
+ Reset: "Nollställ Villkor",
+ odata : ['lika', 'ej lika', 'mindre', 'mindre eller lika','större','större eller lika', 'börjar med','börjar inte med','tillhör','tillhör inte','slutar med','slutar inte med','innehåller','innehåller inte'],
+ groupOps: [ { op: "AND", text: "alla" }, { op: "OR", text: "eller" } ],
+ matchText: " träff",
+ rulesText: " regler"
+ },
+ edit : {
+ addCaption: "Ny Post",
+ editCaption: "Redigera Post",
+ bSubmit: "Spara",
+ bCancel: "Avbryt",
+ bClose: "Stäng",
+ saveData: "Data har ändrats! Spara förändringar?",
+ bYes : "Ja",
+ bNo : "Nej",
+ bExit : "Avbryt",
+ msg: {
+ required:"Fältet är obligatoriskt",
+ number:"Välj korrekt nummer",
+ minValue:"värdet måste vara större än eller lika med",
+ maxValue:"värdet måste vara mindre än eller lika med",
+ email: "är inte korrekt e-post adress",
+ integer: "Var god ange korrekt heltal",
+ date: "Var god ange korrekt datum",
+ url: "är inte en korrekt URL. Prefix måste anges ('http://' or 'https://')",
+ nodefined : " är inte definierad!",
+ novalue : " returvärde måste anges!",
+ customarray : "Custom funktion måste returnera en vektor!",
+ customfcheck : "Custom funktion måste finnas om Custom kontroll sker!"
+ }
+ },
+ view : {
+ caption: "Visa Post",
+ bClose: "Stäng"
+ },
+ del : {
+ caption: "Radera",
+ msg: "Radera markerad(e) post(er)?",
+ bSubmit: "Radera",
+ bCancel: "Avbryt"
+ },
+ nav : {
+ edittext: "",
+ edittitle: "Redigera markerad rad",
+ addtext:"",
+ addtitle: "Skapa ny post",
+ deltext: "",
+ deltitle: "Radera markerad rad",
+ searchtext: "",
+ searchtitle: "Sök poster",
+ refreshtext: "",
+ refreshtitle: "Uppdatera data",
+ alertcap: "Varning",
+ alerttext: "Ingen rad är markerad",
+ viewtext: "",
+ viewtitle: "Visa markerad rad"
+ },
+ col : {
+ caption: "Välj Kolumner",
+ bSubmit: "OK",
+ bCancel: "Avbryt"
+ },
+ errors : {
+ errcap : "Fel",
+ nourl : "URL saknas",
+ norecords: "Det finns inga poster att bearbeta",
+ model : "Antal colNames <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0,00'},
+ currency : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"Kr", defaultValue: '0,00'},
+ date : {
+ dayNames: [
+ "Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör",
+ "Söndag", "Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag"
+ ],
+ monthNames: [
+ "Jan", "Feb", "Mar", "Apr", "Maj", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec",
+ "Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December"
+ ],
+ AmPm : ["fm","em","FM","EM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'Y-m-d',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-tr.js b/ishtar_common/static/js/i18n/grid.locale-tr.js new file mode 100644 index 000000000..4cfa4ec12 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-tr.js @@ -0,0 +1,126 @@ +;(function($){
+/**
+ * jqGrid Turkish Translation
+ * Erhan Gündoğan (erhan@trposta.net)
+ * http://blog.zakkum.com
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "{0}-{1} listeleniyor. Toplam:{2}",
+ emptyrecords: "Kayıt bulunamadı",
+ loadtext: "Yükleniyor...",
+ pgtext : "{0}/{1}. Sayfa"
+ },
+ search : {
+ caption: "Arama...",
+ Find: "Bul",
+ Reset: "Temizle",
+ odata : ['eşit', 'eşit değil', 'daha az', 'daha az veya eşit', 'daha fazla', 'daha fazla veya eşit', 'ile başlayan', 'ile başlamayan', 'içinde', 'içinde değil', 'ile biten', 'ile bitmeyen', 'içeren', 'içermeyen'],
+ groupOps: [ { op: "VE", text: "tüm" }, { op: "VEYA", text: "herhangi" } ],
+ matchText: " uyan",
+ rulesText: " kurallar"
+ },
+ edit : {
+ addCaption: "Kayıt Ekle",
+ editCaption: "Kayıt Düzenle",
+ bSubmit: "Gönder",
+ bCancel: "İptal",
+ bClose: "Kapat",
+ saveData: "Veriler değişti! Kayıt edilsin mi?",
+ bYes : "Evet",
+ bNo : "Hayıt",
+ bExit : "İptal",
+ msg: {
+ required:"Alan gerekli",
+ number:"Lütfen bir numara giriniz",
+ minValue:"girilen değer daha büyük ya da buna eşit olmalıdır",
+ maxValue:"girilen değer daha küçük ya da buna eşit olmalıdır",
+ email: "geçerli bir e-posta adresi değildir",
+ integer: "Lütfen bir tamsayı giriniz",
+ url: "Geçerli bir URL değil. ('http://' or 'https://') ön eki gerekli.",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+ }
+ },
+ view : {
+ caption: "Kayıt Görüntüle",
+ bClose: "Kapat"
+ },
+ del : {
+ caption: "Sil",
+ msg: "Seçilen kayıtlar silinsin mi?",
+ bSubmit: "Sil",
+ bCancel: "İptal"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Seçili satırı düzenle",
+ addtext:" ",
+ addtitle: "Yeni satır ekle",
+ deltext: " ",
+ deltitle: "Seçili satırı sil",
+ searchtext: " ",
+ searchtitle: "Kayıtları bul",
+ refreshtext: "",
+ refreshtitle: "Tabloyu yenile",
+ alertcap: "Uyarı",
+ alerttext: "Lütfen bir satır seçiniz",
+ viewtext: "",
+ viewtitle: "Seçilen satırı görüntüle"
+ },
+ col : {
+ caption: "Sütunları göster/gizle",
+ bSubmit: "Gönder",
+ bCancel: "İptal"
+ },
+ errors : {
+ errcap : "Hata",
+ nourl : "Bir url yapılandırılmamış",
+ norecords: "İşlem yapılacak bir kayıt yok",
+ model : "colNames uzunluğu <> colModel!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0.00'},
+ currency : {decimalSeparator:".", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0.00'},
+ date : {
+ dayNames: [
+ "Paz", "Pts", "Sal", "Çar", "Per", "Cum", "Cts",
+ "Pazar", "Pazartesi", "Salı", "Çarşamba", "Perşembe", "Cuma", "Cumartesi"
+ ],
+ monthNames: [
+ "Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara",
+ "Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'd/m/Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n/j/Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y g:i:s A",
+ MonthDay: "F d",
+ ShortTime: "g:i A",
+ LongTime: "g:i:s A",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/i18n/grid.locale-ua.js b/ishtar_common/static/js/i18n/grid.locale-ua.js new file mode 100644 index 000000000..c9205f8c3 --- /dev/null +++ b/ishtar_common/static/js/i18n/grid.locale-ua.js @@ -0,0 +1,127 @@ +;(function($){
+/**
+ * jqGrid Ukrainian Translation v1.0 02.07.2009
+ * Sergey Dyagovchenko
+ * http://d.sumy.ua
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+**/
+$.jgrid = {
+ defaults : {
+ recordtext: "Перегляд {0} - {1} з {2}",
+ emptyrecords: "Немає записів для перегляду",
+ loadtext: "Завантаження...",
+ pgtext : "Стор. {0} з {1}"
+ },
+ search : {
+ caption: "Пошук...",
+ Find: "Знайти",
+ Reset: "Скидання",
+ odata : ['рівно', 'не рівно', 'менше', 'менше або рівне','більше','більше або рівне', 'починається з','не починається з','знаходиться в','не знаходиться в','закінчується на','не закінчується на','містить','не містить'],
+ groupOps: [ { op: "AND", text: "все" }, { op: "OR", text: "будь-який" } ],
+ matchText: " збігається",
+ rulesText: " правила"
+ },
+ edit : {
+ addCaption: "Додати запис",
+ editCaption: "Змінити запис",
+ bSubmit: "Зберегти",
+ bCancel: "Відміна",
+ bClose: "Закрити",
+ saveData: "До данних були внесені зміни! Зберегти зміни?",
+ bYes : "Так",
+ bNo : "Ні",
+ bExit : "Відміна",
+ msg: {
+ required:"Поле є обов'язковим",
+ number:"Будь ласка, введіть правильне число",
+ minValue:"значення повинне бути більше або дорівнює",
+ maxValue:"значення повинно бути менше або дорівнює",
+ email: "некоректна адреса електронної пошти",
+ integer: "Будь ласка, введення дійсне ціле значення",
+ date: "Будь ласка, введення дійсне значення дати",
+ url: "не дійсний URL. Необхідна приставка ('http://' or 'https://')",
+ nodefined : " is not defined!",
+ novalue : " return value is required!",
+ customarray : "Custom function should return array!",
+ customfcheck : "Custom function should be present in case of custom checking!"
+ }
+ },
+ view : {
+ caption: "Переглянути запис",
+ bClose: "Закрити"
+ },
+ del : {
+ caption: "Видалити",
+ msg: "Видалити обраний запис(и)?",
+ bSubmit: "Видалити",
+ bCancel: "Відміна"
+ },
+ nav : {
+ edittext: " ",
+ edittitle: "Змінити вибраний запис",
+ addtext:" ",
+ addtitle: "Додати новий запис",
+ deltext: " ",
+ deltitle: "Видалити вибраний запис",
+ searchtext: " ",
+ searchtitle: "Знайти записи",
+ refreshtext: "",
+ refreshtitle: "Оновити таблицю",
+ alertcap: "Попередження",
+ alerttext: "Будь ласка, виберіть запис",
+ viewtext: "",
+ viewtitle: "Переглянути обраний запис"
+ },
+ col : {
+ caption: "Показати/Приховати стовпці",
+ bSubmit: "Зберегти",
+ bCancel: "Відміна"
+ },
+ errors : {
+ errcap : "Помилка",
+ nourl : "URL не задан",
+ norecords: "Немає записів для обробки",
+ model : "Число полів не відповідає числу стовпців таблиці!"
+ },
+ formatter : {
+ integer : {thousandsSeparator: " ", defaultValue: '0'},
+ number : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, defaultValue: '0,00'},
+ currency : {decimalSeparator:",", thousandsSeparator: " ", decimalPlaces: 2, prefix: "", suffix:"", defaultValue: '0,00'},
+ date : {
+ dayNames: [
+ "Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб",
+ "Неділя", "Понеділок", "Вівторок", "Середа", "Четвер", "П'ятниця", "Субота"
+ ],
+ monthNames: [
+ "Січ", "Лют", "Бер", "Кві", "Тра", "Чер", "Лип", "Сер", "Вер", "Жов", "Лис", "Гру",
+ "Січень", "Лютий", "Березень", "Квітень", "Травень", "Червень", "Липень", "Серпень", "Вересень", "Жовтень", "Листопад", "Грудень"
+ ],
+ AmPm : ["am","pm","AM","PM"],
+ S: function (j) {return j < 11 || j > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((j - 1) % 10, 3)] : 'th'},
+ srcformat: 'Y-m-d',
+ newformat: 'd.m.Y',
+ masks : {
+ ISO8601Long:"Y-m-d H:i:s",
+ ISO8601Short:"Y-m-d",
+ ShortDate: "n.j.Y",
+ LongDate: "l, F d, Y",
+ FullDateTime: "l, F d, Y G:i:s",
+ MonthDay: "F d",
+ ShortTime: "G:i",
+ LongTime: "G:i:s",
+ SortableDateTime: "Y-m-d\\TH:i:s",
+ UniversalSortableDateTime: "Y-m-d H:i:sO",
+ YearMonth: "F, Y"
+ },
+ reformatAfterEdit : false
+ },
+ baseLinkUrl: '',
+ showAction: '',
+ target: '',
+ checkbox : {disabled:true},
+ idName : 'id'
+ }
+};
+})(jQuery);
diff --git a/ishtar_common/static/js/ishtar.js b/ishtar_common/static/js/ishtar.js new file mode 100644 index 000000000..25fc3c66a --- /dev/null +++ b/ishtar_common/static/js/ishtar.js @@ -0,0 +1,106 @@ + +/* CSRFToken management */ +$.ajaxSetup({ +beforeSend: function(xhr, settings) { + function getCookie(name) { + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } + if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) { + // Only send the token to relative URLs i.e. locally. + xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken')); + } +}}); + + +$(document).ready(function(){ + $("#main_menu > ul > li > ul").hide(); + $("#main_menu ul ul .selected").parents().show(); + var items = new Array('file', 'operation'); + $("#current_file").change(function(){ + $.post('/' + url_path + 'update-current-item/', + {item:'file', value:$("#current_file").val()} + ); + }); + $("#current_operation").change(function(){ + $.post('/' + url_path + 'update-current-item/', + {item:'operation', value:$("#current_operation").val()} + ); + }); +}); + +$("#main_menu ul li").live('click', function(){ + $("#main_menu ul ul").hide('slow'); + $(this).find('ul').show('slow'); +}); + +/* manage help texts */ +$(".help_display").live("click", function(){ + var help_text_id = $(this).attr("href") + "_help"; + $(help_text_id).toggle(); +}) + +var last_window; + +function load_window(url, speed){ + $.ajax({ + url: url, + cache: false, + success:function(html){ + $("#window").append(html); + $("#"+last_window).show(); + }, + error:function(XMLHttpRequest, textStatus, errorThrows){ + } + }); +} + +function load_url(url){ + $.ajax({ + url: url, + cache: false, + success:function(html){}, + error:function(XMLHttpRequest, textStatus, errorThrows){ + } + }); +} + +function open_window(url){ + var newwindow = window.open(url, '_blank', + 'height=400,width=600,scrollbars=yes'); + if (window.focus) {newwindow.focus()} + return false; +} + +function save_and_close_window(name_label, name_pk, item_name, item_pk){ + var main_page = opener.document; + jQuery(main_page).find("#"+name_label).val(item_name); + jQuery(main_page).find("#"+name_pk).val(item_pk); + opener.focus(); + self.close(); +} + +function multiRemoveItem(selItems, name, idx){ + for(id in selItems){ + if(selItems[id] == idx){ + selItems.splice(id, 1); + } + } + jQuery("#selected_"+name+"_"+idx).remove(); +} + +function closeAllWindows(){ + jQuery("#window > div").hide("slow"); + jQuery("#window").html(""); +} diff --git a/ishtar_common/static/js/jquery.jqGrid.min.js b/ishtar_common/static/js/jquery.jqGrid.min.js new file mode 100644 index 000000000..684aba850 --- /dev/null +++ b/ishtar_common/static/js/jquery.jqGrid.min.js @@ -0,0 +1,258 @@ +/* +* jqGrid 4.1.2 - jQuery Grid +* Copyright (c) 2008, Tony Tomov, tony@trirand.com +* Dual licensed under the MIT and GPL licenses +* http://www.opensource.org/licenses/mit-license.php +* http://www.gnu.org/licenses/gpl-2.0.html +* Date:2011-07-20 +* Modules: grid.base.js; jquery.fmatter.js; grid.custom.js; grid.common.js; grid.import.js; JsonXml.js; grid.jqueryui.js; +*/ +(function(b){b.jgrid=b.jgrid||{};b.extend(b.jgrid,{htmlDecode:function(f){if(f&&(f==" "||f==" "||f.length==1&&f.charCodeAt(0)==160))return"";return!f?f:String(f).replace(/&/g,"&").replace(/>/g,">").replace(/</g,"<").replace(/"/g,'"')},htmlEncode:function(f){return!f?f:String(f).replace(/&/g,"&").replace(/>/g,">").replace(/</g,"<").replace(/\"/g,""")},format:function(f){var j=b.makeArray(arguments).slice(1);if(f===undefined)f="";return f.replace(/\{(\d+)\}/g,
+function(h,c){return j[c]})},getCellIndex:function(f){f=b(f);if(f.is("tr"))return-1;f=(!f.is("td")&&!f.is("th")?f.closest("td,th"):f)[0];if(b.browser.msie)return b.inArray(f,f.parentNode.cells);return f.cellIndex},stripHtml:function(f){f+="";var j=/<("[^"]*"|'[^']*'|[^'">])*>/gi;if(f)return(f=f.replace(j,""))&&f!==" "&&f!==" "?f.replace(/\"/g,"'"):"";else return f},stringToDoc:function(f){var j;if(typeof f!=="string")return f;try{j=(new DOMParser).parseFromString(f,"text/xml")}catch(h){j=
+new ActiveXObject("Microsoft.XMLDOM");j.async=false;j.loadXML(f)}return j&&j.documentElement&&j.documentElement.tagName!="parsererror"?j:null},parse:function(f){if(f.substr(0,9)=="while(1);")f=f.substr(9);if(f.substr(0,2)=="/*")f=f.substr(2,f.length-4);f||(f="{}");return b.jgrid.useJSON===true&&typeof JSON==="object"&&typeof JSON.parse==="function"?JSON.parse(f):eval("("+f+")")},parseDate:function(f,j){var h={m:1,d:1,y:1970,h:0,i:0,s:0},c,g,k;c=/[\\\/:_;.,\t\T\s-]/;if(j&&j!==null&&j!==undefined){j=
+b.trim(j);j=j.split(c);f=f.split(c);var l=b.jgrid.formatter.date.monthNames,a=b.jgrid.formatter.date.AmPm,q=function(x,y){if(x===0){if(y==12)y=0}else if(y!=12)y+=12;return y};c=0;for(g=f.length;c<g;c++){if(f[c]=="M"){k=b.inArray(j[c],l);if(k!==-1&&k<12)j[c]=k+1}if(f[c]=="F"){k=b.inArray(j[c],l);if(k!==-1&&k>11)j[c]=k+1-12}if(f[c]=="a"){k=b.inArray(j[c],a);if(k!==-1&&k<2&&j[c]==a[k]){j[c]=k;h.h=q(j[c],h.h)}}if(f[c]=="A"){k=b.inArray(j[c],a);if(k!==-1&&k>1&&j[c]==a[k]){j[c]=k-2;h.h=q(j[c],h.h)}}if(j[c]!==
+undefined)h[f[c].toLowerCase()]=parseInt(j[c],10)}h.m=parseInt(h.m,10)-1;c=h.y;if(c>=70&&c<=99)h.y=1900+h.y;else if(c>=0&&c<=69)h.y=2E3+h.y}return new Date(h.y,h.m,h.d,h.h,h.i,h.s,0)},jqID:function(f){return String(f).replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]\^`{|}~]/g,"\\$&")},guid:1,uidPref:"jqg",randId:function(f){return(f?f:b.jgrid.uidPref)+b.jgrid.guid++},getAccessor:function(f,j){var h,c,g=[],k;if(typeof j==="function")return j(f);h=f[j];if(h===undefined)try{if(typeof j==="string")g=j.split(".");
+if(k=g.length)for(h=f;h&&k--;){c=g.shift();h=h[c]}}catch(l){}return h},ajaxOptions:{},from:function(f){return new function(j,h){if(typeof j=="string")j=b.data(j);var c=this,g=j,k=true,l=false,a=h,q=/[\$,%]/g,x=null,y=null,H=0,L=false,M="",P=[],U=true;if(typeof j=="object"&&j.push){if(j.length>0)U=typeof j[0]!="object"?false:true}else throw"data provides is not an array";this._hasData=function(){return g===null?false:g.length===0?false:true};this._getStr=function(o){var m=[];l&&m.push("jQuery.trim(");
+m.push("String("+o+")");l&&m.push(")");k||m.push(".toLowerCase()");return m.join("")};this._strComp=function(o){return typeof o=="string"?".toString()":""};this._group=function(o,m){return{field:o.toString(),unique:m,items:[]}};this._toStr=function(o){if(l)o=b.trim(o);k||(o=o.toLowerCase());return o=o.toString().replace(/\\/g,"\\\\").replace(/\"/g,'\\"')};this._funcLoop=function(o){var m=[];b.each(g,function(r,D){m.push(o(D))});return m};this._append=function(o){var m;if(a===null)a="";else a+=M===
+""?" && ":M;for(m=0;m<H;m++)a+="(";if(L)a+="!";a+="("+o+")";L=false;M="";H=0};this._setCommand=function(o,m){x=o;y=m};this._resetNegate=function(){L=false};this._repeatCommand=function(o,m){if(x===null)return c;if(o!==null&&m!==null)return x(o,m);if(y===null)return x(o);if(!U)return x(o);return x(y,o)};this._equals=function(o,m){return c._compare(o,m,1)===0};this._compare=function(o,m,r){if(r===undefined)r=1;if(o===undefined)o=null;if(m===undefined)m=null;if(o===null&&m===null)return 0;if(o===null&&
+m!==null)return 1;if(o!==null&&m===null)return-1;if(!k&&typeof o!=="number"&&typeof m!=="number"){o=String(o).toLowerCase();m=String(m).toLowerCase()}if(o<m)return-r;if(o>m)return r;return 0};this._performSort=function(){if(P.length!==0)g=c._doSort(g,0)};this._doSort=function(o,m){var r=P[m].by,D=P[m].dir,T=P[m].type,I=P[m].datefmt;if(m==P.length-1)return c._getOrder(o,r,D,T,I);m++;r=c._getGroup(o,r,D,T,I);D=[];for(T=0;T<r.length;T++){I=c._doSort(r[T].items,m);for(var C=0;C<I.length;C++)D.push(I[C])}return D};
+this._getOrder=function(o,m,r,D,T){var I=[],C=[],ca=r=="a"?1:-1,V,fa;if(D===undefined)D="text";fa=D=="float"||D=="number"||D=="currency"||D=="numeric"?function(R){R=parseFloat(String(R).replace(q,""));return isNaN(R)?0:R}:D=="int"||D=="integer"?function(R){return R?parseFloat(String(R).replace(q,"")):0}:D=="date"||D=="datetime"?function(R){return b.jgrid.parseDate(T,R).getTime()}:b.isFunction(D)?D:function(R){R||(R="");return b.trim(String(R).toUpperCase())};b.each(o,function(R,$){V=m!==""?b.jgrid.getAccessor($,
+m):$;if(V===undefined)V="";V=fa(V,$);C.push({vSort:V,index:R})});C.sort(function(R,$){R=R.vSort;$=$.vSort;return c._compare(R,$,ca)});D=0;for(var oa=o.length;D<oa;){r=C[D].index;I.push(o[r]);D++}return I};this._getGroup=function(o,m,r,D,T){var I=[],C=null,ca=null,V;b.each(c._getOrder(o,m,r,D,T),function(fa,oa){V=b.jgrid.getAccessor(oa,m);if(V===undefined)V="";if(!c._equals(ca,V)){ca=V;C!==null&&I.push(C);C=c._group(m,V)}C.items.push(oa)});C!==null&&I.push(C);return I};this.ignoreCase=function(){k=
+false;return c};this.useCase=function(){k=true;return c};this.trim=function(){l=true;return c};this.noTrim=function(){l=false;return c};this.execute=function(){var o=a,m=[];if(o===null)return c;b.each(g,function(){eval(o)&&m.push(this)});g=m;return c};this.data=function(){return g};this.select=function(o){c._performSort();if(!c._hasData())return[];c.execute();if(b.isFunction(o)){var m=[];b.each(g,function(r,D){m.push(o(D))});return m}return g};this.hasMatch=function(){if(!c._hasData())return false;
+c.execute();return g.length>0};this.andNot=function(o,m,r){L=!L;return c.and(o,m,r)};this.orNot=function(o,m,r){L=!L;return c.or(o,m,r)};this.not=function(o,m,r){return c.andNot(o,m,r)};this.and=function(o,m,r){M=" && ";if(o===undefined)return c;return c._repeatCommand(o,m,r)};this.or=function(o,m,r){M=" || ";if(o===undefined)return c;return c._repeatCommand(o,m,r)};this.orBegin=function(){H++;return c};this.orEnd=function(){if(a!==null)a+=")";return c};this.isNot=function(o){L=!L;return c.is(o)};
+this.is=function(o){c._append("this."+o);c._resetNegate();return c};this._compareValues=function(o,m,r,D,T){var I;I=U?"jQuery.jgrid.getAccessor(this,'"+m+"')":"this";if(r===undefined)r=null;var C=r,ca=T.stype===undefined?"text":T.stype;if(r!==null)switch(ca){case "int":case "integer":C=isNaN(Number(C))||C===""?"0":C;I="parseInt("+I+",10)";C="parseInt("+C+",10)";break;case "float":case "number":case "numeric":C=String(C).replace(q,"");C=isNaN(Number(C))||C===""?"0":C;I="parseFloat("+I+")";C="parseFloat("+
+C+")";break;case "date":case "datetime":C=String(b.jgrid.parseDate(T.newfmt||"Y-m-d",C).getTime());I='jQuery.jgrid.parseDate("'+T.srcfmt+'",'+I+").getTime()";break;default:I=c._getStr(I);C=c._getStr('"'+c._toStr(C)+'"')}c._append(I+" "+D+" "+C);c._setCommand(o,m);c._resetNegate();return c};this.equals=function(o,m,r){return c._compareValues(c.equals,o,m,"==",r)};this.notEquals=function(o,m,r){return c._compareValues(c.equals,o,m,"!==",r)};this.isNull=function(o,m,r){return c._compareValues(c.equals,
+o,null,"===",r)};this.greater=function(o,m,r){return c._compareValues(c.greater,o,m,">",r)};this.less=function(o,m,r){return c._compareValues(c.less,o,m,"<",r)};this.greaterOrEquals=function(o,m,r){return c._compareValues(c.greaterOrEquals,o,m,">=",r)};this.lessOrEquals=function(o,m,r){return c._compareValues(c.lessOrEquals,o,m,"<=",r)};this.startsWith=function(o,m){var r=m===undefined||m===null?o:m;r=l?b.trim(r.toString()).length:r.toString().length;if(U)c._append(c._getStr("jQuery.jgrid.getAccessor(this,'"+
+o+"')")+".substr(0,"+r+") == "+c._getStr('"'+c._toStr(m)+'"'));else{r=l?b.trim(m.toString()).length:m.toString().length;c._append(c._getStr("this")+".substr(0,"+r+") == "+c._getStr('"'+c._toStr(o)+'"'))}c._setCommand(c.startsWith,o);c._resetNegate();return c};this.endsWith=function(o,m){var r=m===undefined||m===null?o:m;r=l?b.trim(r.toString()).length:r.toString().length;U?c._append(c._getStr("jQuery.jgrid.getAccessor(this,'"+o+"')")+".substr("+c._getStr("jQuery.jgrid.getAccessor(this,'"+o+"')")+
+".length-"+r+","+r+') == "'+c._toStr(m)+'"'):c._append(c._getStr("this")+".substr("+c._getStr("this")+'.length-"'+c._toStr(o)+'".length,"'+c._toStr(o)+'".length) == "'+c._toStr(o)+'"');c._setCommand(c.endsWith,o);c._resetNegate();return c};this.contains=function(o,m){U?c._append(c._getStr("jQuery.jgrid.getAccessor(this,'"+o+"')")+'.indexOf("'+c._toStr(m)+'",0) > -1'):c._append(c._getStr("this")+'.indexOf("'+c._toStr(o)+'",0) > -1');c._setCommand(c.contains,o);c._resetNegate();return c};this.groupBy=
+function(o,m,r,D){if(!c._hasData())return null;return c._getGroup(g,o,m,r,D)};this.orderBy=function(o,m,r,D){m=m===undefined||m===null?"a":b.trim(m.toString().toLowerCase());if(r===null||r===undefined)r="text";if(D===null||D===undefined)D="Y-m-d";if(m=="desc"||m=="descending")m="d";if(m=="asc"||m=="ascending")m="a";P.push({by:o,dir:m,type:r,datefmt:D});return c};return c}(f,null)},extend:function(f){b.extend(b.fn.jqGrid,f);this.no_legacy_api||b.fn.extend(f)}});b.fn.jqGrid=function(f){if(typeof f==
+"string"){var j=b.jgrid.getAccessor(b.fn.jqGrid,f);if(!j)throw"jqGrid - No such method: "+f;var h=b.makeArray(arguments).slice(1);return j.apply(this,h)}return this.each(function(){if(!this.grid){var c=b.extend(true,{url:"",height:150,page:1,rowNum:20,rowTotal:null,records:0,pager:"",pgbuttons:true,pginput:true,colModel:[],rowList:[],colNames:[],sortorder:"asc",sortname:"",datatype:"xml",mtype:"GET",altRows:false,selarrrow:[],savedRow:[],shrinkToFit:true,xmlReader:{},jsonReader:{},subGrid:false,subGridModel:[],
+reccount:0,lastpage:0,lastsort:0,selrow:null,beforeSelectRow:null,onSelectRow:null,onSortCol:null,ondblClickRow:null,onRightClickRow:null,onPaging:null,onSelectAll:null,loadComplete:null,gridComplete:null,loadError:null,loadBeforeSend:null,afterInsertRow:null,beforeRequest:null,onHeaderClick:null,viewrecords:false,loadonce:false,multiselect:false,multikey:false,editurl:null,search:false,caption:"",hidegrid:true,hiddengrid:false,postData:{},userData:{},treeGrid:false,treeGridModel:"nested",treeReader:{},
+treeANode:-1,ExpandColumn:null,tree_root_level:0,prmNames:{page:"page",rows:"rows",sort:"sidx",order:"sord",search:"_search",nd:"nd",id:"id",oper:"oper",editoper:"edit",addoper:"add",deloper:"del",subgridid:"id",npage:null,totalrows:"totalrows"},forceFit:false,gridstate:"visible",cellEdit:false,cellsubmit:"remote",nv:0,loadui:"enable",toolbar:[false,""],scroll:false,multiboxonly:false,deselectAfterSort:true,scrollrows:false,autowidth:false,scrollOffset:18,cellLayout:5,subGridWidth:20,multiselectWidth:20,
+gridview:false,rownumWidth:25,rownumbers:false,pagerpos:"center",recordpos:"right",footerrow:false,userDataOnFooter:false,hoverrows:true,altclass:"ui-priority-secondary",viewsortcols:[false,"vertical",true],resizeclass:"",autoencode:false,remapColumns:[],ajaxGridOptions:{},direction:"ltr",toppager:false,headertitles:false,scrollTimeout:40,data:[],_index:{},grouping:false,groupingView:{groupField:[],groupOrder:[],groupText:[],groupColumnShow:[],groupSummary:[],showSummaryOnHide:false,sortitems:[],
+sortnames:[],groupDataSorted:false,summary:[],summaryval:[],plusicon:"ui-icon-circlesmall-plus",minusicon:"ui-icon-circlesmall-minus"},ignoreCase:false,cmTemplate:{}},b.jgrid.defaults,f||{}),g={headers:[],cols:[],footers:[],dragStart:function(e,d,i){this.resizing={idx:e,startX:d.clientX,sOL:i[0]};this.hDiv.style.cursor="col-resize";this.curGbox=b("#rs_m"+b.jgrid.jqID(c.id),"#gbox_"+b.jgrid.jqID(c.id));this.curGbox.css({display:"block",left:i[0],top:i[1],height:i[2]});b.isFunction(c.resizeStart)&&
+c.resizeStart.call(this,d,e);document.onselectstart=function(){return false}},dragMove:function(e){if(this.resizing){var d=e.clientX-this.resizing.startX;e=this.headers[this.resizing.idx];var i=c.direction==="ltr"?e.width+d:e.width-d,n;if(i>33){this.curGbox.css({left:this.resizing.sOL+d});if(c.forceFit===true){n=this.headers[this.resizing.idx+c.nv];d=c.direction==="ltr"?n.width-d:n.width+d;if(d>33){e.newWidth=i;n.newWidth=d}}else{this.newWidth=c.direction==="ltr"?c.tblwidth+d:c.tblwidth-d;e.newWidth=
+i}}}},dragEnd:function(){this.hDiv.style.cursor="default";if(this.resizing){var e=this.resizing.idx,d=this.headers[e].newWidth||this.headers[e].width;d=parseInt(d,10);this.resizing=false;b("#rs_m"+b.jgrid.jqID(c.id)).css("display","none");c.colModel[e].width=d;this.headers[e].width=d;this.headers[e].el.style.width=d+"px";this.cols[e].style.width=d+"px";if(this.footers.length>0)this.footers[e].style.width=d+"px";if(c.forceFit===true){d=this.headers[e+c.nv].newWidth||this.headers[e+c.nv].width;this.headers[e+
+c.nv].width=d;this.headers[e+c.nv].el.style.width=d+"px";this.cols[e+c.nv].style.width=d+"px";if(this.footers.length>0)this.footers[e+c.nv].style.width=d+"px";c.colModel[e+c.nv].width=d}else{c.tblwidth=this.newWidth||c.tblwidth;b("table:first",this.bDiv).css("width",c.tblwidth+"px");b("table:first",this.hDiv).css("width",c.tblwidth+"px");this.hDiv.scrollLeft=this.bDiv.scrollLeft;if(c.footerrow){b("table:first",this.sDiv).css("width",c.tblwidth+"px");this.sDiv.scrollLeft=this.bDiv.scrollLeft}}b.isFunction(c.resizeStop)&&
+c.resizeStop.call(this,d,e)}this.curGbox=null;document.onselectstart=function(){return true}},populateVisible:function(){g.timer&&clearTimeout(g.timer);g.timer=null;var e=b(g.bDiv).height();if(e){var d=b("table:first",g.bDiv),i,n;if(d[0].rows.length)try{n=(i=d[0].rows[1])?b(i).outerHeight()||g.prevRowHeight:g.prevRowHeight}catch(p){n=g.prevRowHeight}if(n){g.prevRowHeight=n;var A=c.rowNum;i=g.scrollTop=g.bDiv.scrollTop;var s=Math.round(d.position().top)-i,E=s+d.height();n*=A;var u,z,w;if(E<e&&s<=0&&
+(c.lastpage===undefined||parseInt((E+i+n-1)/n,10)<=c.lastpage)){z=parseInt((e-E+n-1)/n,10);if(E>=0||z<2||c.scroll===true){u=Math.round((E+i)/n)+1;s=-1}else s=1}if(s>0){u=parseInt(i/n,10)+1;z=parseInt((i+e)/n,10)+2-u;w=true}if(z)if(!(c.lastpage&&u>c.lastpage||c.lastpage==1||u===c.page&&u===c.lastpage))if(g.hDiv.loading)g.timer=setTimeout(g.populateVisible,c.scrollTimeout);else{c.page=u;if(w){g.selectionPreserver(d[0]);g.emptyRows(g.bDiv,false,false)}g.populate(z)}}}},scrollGrid:function(e){if(c.scroll){var d=
+g.bDiv.scrollTop;if(g.scrollTop===undefined)g.scrollTop=0;if(d!=g.scrollTop){g.scrollTop=d;g.timer&&clearTimeout(g.timer);g.timer=setTimeout(g.populateVisible,c.scrollTimeout)}}g.hDiv.scrollLeft=g.bDiv.scrollLeft;if(c.footerrow)g.sDiv.scrollLeft=g.bDiv.scrollLeft;e&&e.stopPropagation()},selectionPreserver:function(e){var d=e.p,i=d.selrow,n=d.selarrrow?b.makeArray(d.selarrrow):null,p=e.grid.bDiv.scrollLeft,A=d.gridComplete;d.gridComplete=function(){d.selrow=null;d.selarrrow=[];if(d.multiselect&&n&&
+n.length>0)for(var s=0;s<n.length;s++)n[s]!=i&&b(e).jqGrid("setSelection",n[s],false);i&&b(e).jqGrid("setSelection",i,false);e.grid.bDiv.scrollLeft=p;d.gridComplete=A;d.gridComplete&&A()}}};if(this.tagName.toUpperCase()!="TABLE")alert("Element is not a table");else{b(this).empty().attr("tabindex","1");this.p=c;var k,l,a;if(this.p.colNames.length===0)for(k=0;k<this.p.colModel.length;k++)this.p.colNames[k]=this.p.colModel[k].label||this.p.colModel[k].name;if(this.p.colNames.length!==this.p.colModel.length)alert(b.jgrid.errors.model);
+else{var q=b("<div class='ui-jqgrid-view'></div>"),x,y=b.browser.msie?true:false,H=b.browser.webkit||b.browser.safari?true:false;a=this;a.p.direction=b.trim(a.p.direction.toLowerCase());if(b.inArray(a.p.direction,["ltr","rtl"])==-1)a.p.direction="ltr";l=a.p.direction;b(q).insertBefore(this);b(this).appendTo(q).removeClass("scroll");var L=b("<div class='ui-jqgrid ui-widget ui-widget-content ui-corner-all'></div>");b(L).insertBefore(q).attr({id:"gbox_"+this.id,dir:l});b(q).appendTo(L).attr("id","gview_"+
+this.id);x=y&&b.browser.version<=6?'<iframe style="display:block;position:absolute;z-index:-1;filter:Alpha(Opacity=\'0\');" src="javascript:false;"></iframe>':"";b("<div class='ui-widget-overlay jqgrid-overlay' id='lui_"+this.id+"'></div>").append(x).insertBefore(q);b("<div class='loading ui-state-default ui-state-active' id='load_"+this.id+"'>"+this.p.loadtext+"</div>").insertBefore(q);b(this).attr({cellspacing:"0",cellpadding:"0",border:"0",role:"grid","aria-multiselectable":!!this.p.multiselect,
+"aria-labelledby":"gbox_"+this.id});var M=function(e,d){e=parseInt(e,10);return isNaN(e)?d?d:0:e},P=function(e,d,i,n,p,A){var s=a.p.colModel[e],E=s.align,u='style="',z=s.classes,w=s.name,t=[];if(E)u+="text-align:"+E+";";if(s.hidden===true)u+="display:none;";if(d===0)u+="width: "+g.headers[e].width+"px;";else if(s.cellattr&&b.isFunction(s.cellattr))if((e=s.cellattr.call(a,p,i,n,s,A))&&typeof e==="string"){e=e.replace(/style/i,"style").replace(/title/i,"title");if(e.indexOf("title")>-1)s.title=false;
+if(e.indexOf("class")>-1)z=undefined;t=e.split("style");if(t.length===2){t[1]=b.trim(t[1].replace("=",""));if(t[1].indexOf("'")===0||t[1].indexOf('"')===0)t[1]=t[1].substring(1);u+=t[1].replace(/'/gi,'"')}else u+='"'}if(!t.length){t[0]="";u+='"'}u+=(z!==undefined?' class="'+z+'"':"")+(s.title&&i?' title="'+b.jgrid.stripHtml(i)+'"':"");u+=' aria-describedby="'+a.p.id+"_"+w+'"';return u+t[0]},U=function(e){return e===undefined||e===null||e===""?" ":a.p.autoencode?b.jgrid.htmlEncode(e):e+""},o=
+function(e,d,i,n,p){var A=a.p.colModel[i];if(typeof A.formatter!=="undefined"){e={rowId:e,colModel:A,gid:a.p.id,pos:i};d=b.isFunction(A.formatter)?A.formatter.call(a,d,e,n,p):b.fmatter?b.fn.fmatter(A.formatter,d,e,n,p):U(d)}else d=U(d);return d},m=function(e,d,i,n,p){d=o(e,d,i,p,"add");return'<td role="gridcell" '+P(i,n,d,p,e,true)+">"+d+"</td>"},r=function(e,d,i){var n='<input role="checkbox" type="checkbox" id="jqg_'+a.p.id+"_"+e+'" class="cbox" name="jqg_'+a.p.id+"_"+e+'"/>';return'<td role="gridcell" '+
+P(d,i,"",null,e,true)+">"+n+"</td>"},D=function(e,d,i,n){i=(parseInt(i,10)-1)*parseInt(n,10)+1+d;return'<td role="gridcell" class="ui-state-default jqgrid-rownum" '+P(e,d,i,null,d,true)+">"+i+"</td>"},T=function(e){var d,i=[],n=0,p;for(p=0;p<a.p.colModel.length;p++){d=a.p.colModel[p];if(d.name!=="cb"&&d.name!=="subgrid"&&d.name!=="rn"){i[n]=e=="local"?d.name:e=="xml"?d.xmlmap||d.name:d.jsonmap||d.name;n++}}return i},I=function(e){var d=a.p.remapColumns;if(!d||!d.length)d=b.map(a.p.colModel,function(i,
+n){return n});if(e)d=b.map(d,function(i){return i<e?null:i-e});return d},C=function(e,d,i){if(a.p.deepempty)b("#"+b.jgrid.jqID(a.p.id)+" tbody:first tr:gt(0)").remove();else{var n=b("#"+b.jgrid.jqID(a.p.id)+" tbody:first tr:first")[0];b("#"+b.jgrid.jqID(a.p.id)+" tbody:first").empty().append(n)}if(d&&a.p.scroll){b(">div:first",e).css({height:"auto"}).children("div:first").css({height:0,display:"none"});e.scrollTop=0}if(i===true)if(a.p.treeGrid===true){a.p.data=[];a.p._index={}}},ca=function(){var e=
+a.p.data.length,d,i,n;d=a.p.rownumbers===true?1:0;i=a.p.multiselect===true?1:0;n=a.p.subGrid===true?1:0;d=a.p.keyIndex===false||a.p.loadonce===true?a.p.localReader.id:a.p.colModel[a.p.keyIndex+i+n+d].name;for(i=0;i<e;i++){n=b.jgrid.getAccessor(a.p.data[i],d);a.p._index[n]=i}},V=function(e,d,i,n,p){var A=new Date,s=a.p.datatype!="local"&&a.p.loadonce||a.p.datatype=="xmlstring",E=a.p.datatype=="local"?"local":"xml";if(s){a.p.data=[];a.p._index={};a.p.localReader.id="_id_"}a.p.reccount=0;if(b.isXMLDoc(e)){if(a.p.treeANode===
+-1&&!a.p.scroll){C(d,false,true);i=1}else i=i>1?i:1;var u,z,w=0,t,F=0,S=0,N=0,K,O=[],Y,J={},v,B,G=[],ia=a.p.altRows===true?" "+a.p.altclass:"";a.p.xmlReader.repeatitems||(O=T(E));K=a.p.keyIndex===false?a.p.xmlReader.id:a.p.keyIndex;if(O.length>0&&!isNaN(K)){if(a.p.remapColumns&&a.p.remapColumns.length)K=b.inArray(K,a.p.remapColumns);K=O[K]}E=(K+"").indexOf("[")===-1?O.length?function(ga,aa){return b(K,ga).text()||aa}:function(ga,aa){return b(a.p.xmlReader.cell,ga).eq(K).text()||aa}:function(ga,aa){return ga.getAttribute(K.replace(/[\[\]]/g,
+""))||aa};a.p.userData={};b(a.p.xmlReader.page,e).each(function(){a.p.page=this.textContent||this.text||0});b(a.p.xmlReader.total,e).each(function(){a.p.lastpage=this.textContent||this.text;if(a.p.lastpage===undefined)a.p.lastpage=1});b(a.p.xmlReader.records,e).each(function(){a.p.records=this.textContent||this.text||0});b(a.p.xmlReader.userdata,e).each(function(){a.p.userData[this.getAttribute("name")]=this.textContent||this.text});(e=b(a.p.xmlReader.root+" "+a.p.xmlReader.row,e))||(e=[]);var ba=
+e.length,W=0,Z={},ha;if(e&&ba){ha=parseInt(a.p.rowNum,10);var pa=a.p.scroll?b.jgrid.randId():1;if(p)ha*=p+1;p=b.isFunction(a.p.afterInsertRow);var qa="";if(a.p.grouping&&a.p.groupingView.groupCollapse===true)qa=' style="display:none;"';for(;W<ba;){v=e[W];B=E(v,pa+W);u=i===0?0:i+1;u=(u+W)%2==1?ia:"";G.push("<tr"+qa+' id="'+B+'" tabindex="-1" role="row" class ="ui-widget-content jqgrow ui-row-'+a.p.direction+""+u+'">');if(a.p.rownumbers===true){G.push(D(0,W,a.p.page,a.p.rowNum));N=1}if(a.p.multiselect===
+true){G.push(r(B,N,W));F=1}if(a.p.subGrid===true){G.push(b(a).jqGrid("addSubGridCell",F+N,W+i));S=1}if(a.p.xmlReader.repeatitems){Y||(Y=I(F+S+N));var Ba=b(a.p.xmlReader.cell,v);b.each(Y,function(ga){var aa=Ba[this];if(!aa)return false;t=aa.textContent||aa.text;J[a.p.colModel[ga+F+S+N].name]=t;G.push(m(B,t,ga+F+S+N,W+i,v))})}else for(u=0;u<O.length;u++){t=b(O[u],v).text();J[a.p.colModel[u+F+S+N].name]=t;G.push(m(B,t,u+F+S+N,W+i,v))}G.push("</tr>");if(a.p.grouping){u=a.p.groupingView.groupField.length;
+for(var xa=[],ya=0;ya<u;ya++)xa.push(J[a.p.groupingView.groupField[ya]]);Z=b(a).jqGrid("groupingPrepare",G,xa,Z,J);G=[]}if(s||a.p.treeGrid===true){J._id_=B;a.p.data.push(J);a.p._index[B]=a.p.data.length-1}if(a.p.gridview===false){b("tbody:first",d).append(G.join(""));p&&a.p.afterInsertRow.call(a,B,J,v);G=[]}J={};w++;W++;if(w==ha)break}}if(a.p.gridview===true){z=a.p.treeANode>-1?a.p.treeANode:0;if(a.p.grouping){b(a).jqGrid("groupingRender",Z,a.p.colModel.length);Z=null}else a.p.treeGrid===true&&z>
+0?b(a.rows[z]).after(G.join("")):b("tbody:first",d).append(G.join(""))}if(a.p.subGrid===true)try{b(a).jqGrid("addSubGrid",F+N)}catch(Ha){}a.p.totaltime=new Date-A;if(w>0)if(a.p.records===0)a.p.records=ba;G=null;if(a.p.treeGrid===true)try{b(a).jqGrid("setTreeNode",z+1,w+z+1)}catch(Ia){}if(!a.p.treeGrid&&!a.p.scroll)a.grid.bDiv.scrollTop=0;a.p.reccount=w;a.p.treeANode=-1;a.p.userDataOnFooter&&b(a).jqGrid("footerData","set",a.p.userData,true);if(s){a.p.records=ba;a.p.lastpage=Math.ceil(ba/ha)}n||a.updatepager(false,
+true);if(s)for(;w<ba;){v=e[w];B=E(v,w);if(a.p.xmlReader.repeatitems){Y||(Y=I(F+S+N));var Ea=b(a.p.xmlReader.cell,v);b.each(Y,function(ga){var aa=Ea[this];if(!aa)return false;t=aa.textContent||aa.text;J[a.p.colModel[ga+F+S+N].name]=t})}else for(u=0;u<O.length;u++){t=b(O[u],v).text();J[a.p.colModel[u+F+S+N].name]=t}J._id_=B;a.p.data.push(J);a.p._index[B]=a.p.data.length-1;J={};w++}}},fa=function(e,d,i,n,p){var A=new Date;if(e){if(a.p.treeANode===-1&&!a.p.scroll){C(d,false,true);i=1}else i=i>1?i:1;var s,
+E=a.p.datatype!="local"&&a.p.loadonce||a.p.datatype=="jsonstring";if(E){a.p.data=[];a.p._index={};a.p.localReader.id="_id_"}a.p.reccount=0;if(a.p.datatype=="local"){d=a.p.localReader;s="local"}else{d=a.p.jsonReader;s="json"}var u=0,z,w,t=[],F,S=0,N=0,K=0,O,Y,J={},v,B,G=[],ia=a.p.altRows===true?" "+a.p.altclass:"";a.p.page=b.jgrid.getAccessor(e,d.page)||0;O=b.jgrid.getAccessor(e,d.total);a.p.lastpage=O===undefined?1:O;a.p.records=b.jgrid.getAccessor(e,d.records)||0;a.p.userData=b.jgrid.getAccessor(e,
+d.userdata)||{};d.repeatitems||(F=t=T(s));s=a.p.keyIndex===false?d.id:a.p.keyIndex;if(t.length>0&&!isNaN(s)){if(a.p.remapColumns&&a.p.remapColumns.length)s=b.inArray(s,a.p.remapColumns);s=t[s]}(Y=b.jgrid.getAccessor(e,d.root))||(Y=[]);O=Y.length;e=0;var ba=parseInt(a.p.rowNum,10),W=a.p.scroll?b.jgrid.randId():1;if(p)ba*=p+1;var Z=b.isFunction(a.p.afterInsertRow),ha={},pa="";if(a.p.grouping&&a.p.groupingView.groupCollapse===true)pa=' style="display:none;"';for(;e<O;){p=Y[e];B=b.jgrid.getAccessor(p,
+s);if(B===undefined){B=W+e;if(t.length===0)if(d.cell)B=b.jgrid.getAccessor(p,d.cell)[s]||B}z=i===1?0:i;z=(z+e)%2==1?ia:"";G.push("<tr"+pa+' id="'+B+'" tabindex="-1" role="row" class= "ui-widget-content jqgrow ui-row-'+a.p.direction+""+z+'">');if(a.p.rownumbers===true){G.push(D(0,e,a.p.page,a.p.rowNum));K=1}if(a.p.multiselect){G.push(r(B,K,e));S=1}if(a.p.subGrid){G.push(b(a).jqGrid("addSubGridCell",S+K,e+i));N=1}if(d.repeatitems){if(d.cell)p=b.jgrid.getAccessor(p,d.cell);F||(F=I(S+N+K))}for(w=0;w<
+F.length;w++){z=b.jgrid.getAccessor(p,F[w]);G.push(m(B,z,w+S+N+K,e+i,p));J[a.p.colModel[w+S+N+K].name]=z}G.push("</tr>");if(a.p.grouping){z=a.p.groupingView.groupField.length;w=[];for(var qa=0;qa<z;qa++)w.push(J[a.p.groupingView.groupField[qa]]);ha=b(a).jqGrid("groupingPrepare",G,w,ha,J);G=[]}if(E||a.p.treeGrid===true){J._id_=B;a.p.data.push(J);a.p._index[B]=a.p.data.length-1}if(a.p.gridview===false){b("#"+b.jgrid.jqID(a.p.id)+" tbody:first").append(G.join(""));Z&&a.p.afterInsertRow.call(a,B,J,p);
+G=[]}J={};u++;e++;if(u==ba)break}if(a.p.gridview===true){v=a.p.treeANode>-1?a.p.treeANode:0;if(a.p.grouping)b(a).jqGrid("groupingRender",ha,a.p.colModel.length);else a.p.treeGrid===true&&v>0?b(a.rows[v]).after(G.join("")):b("#"+b.jgrid.jqID(a.p.id)+" tbody:first").append(G.join(""))}if(a.p.subGrid===true)try{b(a).jqGrid("addSubGrid",S+K)}catch(Ba){}a.p.totaltime=new Date-A;if(u>0)if(a.p.records===0)a.p.records=O;if(a.p.treeGrid===true)try{b(a).jqGrid("setTreeNode",v+1,u+v+1)}catch(xa){}if(!a.p.treeGrid&&
+!a.p.scroll)a.grid.bDiv.scrollTop=0;a.p.reccount=u;a.p.treeANode=-1;a.p.userDataOnFooter&&b(a).jqGrid("footerData","set",a.p.userData,true);if(E){a.p.records=O;a.p.lastpage=Math.ceil(O/ba)}n||a.updatepager(false,true);if(E)for(;u<O&&Y[u];){p=Y[u];B=b.jgrid.getAccessor(p,s);if(B===undefined){B=W+u;if(t.length===0)if(d.cell)B=b.jgrid.getAccessor(p,d.cell)[s]||B}if(p){if(d.repeatitems){if(d.cell)p=b.jgrid.getAccessor(p,d.cell);F||(F=I(S+N+K))}for(w=0;w<F.length;w++){z=b.jgrid.getAccessor(p,F[w]);J[a.p.colModel[w+
+S+N+K].name]=z}J._id_=B;a.p.data.push(J);a.p._index[B]=a.p.data.length-1;J={}}u++}}},oa=function(){function e(v){var B=0,G,ia,ba,W,Z;if(v.groups!==undefined){(ia=v.groups.length&&v.groupOp.toString().toUpperCase()==="OR")&&t.orBegin();for(G=0;G<v.groups.length;G++){B>0&&ia&&t.or();try{e(v.groups[G])}catch(ha){alert(ha)}B++}ia&&t.orEnd()}if(v.rules!==undefined){if(B>0){ia=t.select();t=b.jgrid.from(ia)}try{(ba=v.rules.length&&v.groupOp.toString().toUpperCase()==="OR")&&t.orBegin();for(G=0;G<v.rules.length;G++){Z=
+v.rules[G];W=v.groupOp.toString().toUpperCase();if(w[Z.op]&&Z.field){if(B>0&&W&&W==="OR")t=t.or();t=w[Z.op](t,W)(Z.field,Z.data,n[Z.field])}B++}ba&&t.orEnd()}catch(pa){alert(pa)}}}var d,i=false,n={},p=[],A=[],s,E,u;if(b.isArray(a.p.data)){var z=a.p.grouping?a.p.groupingView:false;b.each(a.p.colModel,function(){E=this.sorttype||"text";if(E=="date"||E=="datetime"){if(this.formatter&&typeof this.formatter==="string"&&this.formatter=="date"){s=this.formatoptions&&this.formatoptions.srcformat?this.formatoptions.srcformat:
+b.jgrid.formatter.date.srcformat;u=this.formatoptions&&this.formatoptions.newformat?this.formatoptions.newformat:b.jgrid.formatter.date.newformat}else s=u=this.datefmt||"Y-m-d";n[this.name]={stype:E,srcfmt:s,newfmt:u}}else n[this.name]={stype:E,srcfmt:"",newfmt:""};if(a.p.grouping&&this.name==z.groupField[0]){var v=this.name;if(typeof this.index!="undefined")v=this.index;p[0]=n[v];A.push(v)}if(!i&&(this.index==a.p.sortname||this.name==a.p.sortname)){d=this.name;i=true}});if(a.p.treeGrid)b(a).jqGrid("SortTree",
+d,a.p.sortorder,n[d].stype,n[d].srcfmt);else{var w={eq:function(v){return v.equals},ne:function(v){return v.notEquals},lt:function(v){return v.less},le:function(v){return v.lessOrEquals},gt:function(v){return v.greater},ge:function(v){return v.greaterOrEquals},cn:function(v){return v.contains},nc:function(v,B){return B==="OR"?v.orNot().contains:v.andNot().contains},bw:function(v){return v.startsWith},bn:function(v,B){return B==="OR"?v.orNot().startsWith:v.andNot().startsWith},en:function(v,B){return B===
+"OR"?v.orNot().endsWith:v.andNot().endsWith},ew:function(v){return v.endsWith},ni:function(v,B){return B==="OR"?v.orNot().equals:v.andNot().equals},"in":function(v){return v.equals},nu:function(v){return v.isNull},nn:function(v,B){return B==="OR"?v.orNot().isNull:v.andNot().isNull}},t=b.jgrid.from(a.p.data);if(a.p.ignoreCase)t=t.ignoreCase();if(a.p.search===true){var F=a.p.postData.filters;if(F){if(typeof F=="string")F=b.jgrid.parse(F);e(F)}else try{t=w[a.p.postData.searchOper](t)(a.p.postData.searchField,
+a.p.postData.searchString,n[a.p.postData.searchField])}catch(S){}}if(a.p.grouping){t.orderBy(A,z.groupOrder[0],p[0].stype,p[0].srcfmt);z.groupDataSorted=true}if(d&&a.p.sortorder&&i)a.p.sortorder.toUpperCase()=="DESC"?t.orderBy(a.p.sortname,"d",n[d].stype,n[d].srcfmt):t.orderBy(a.p.sortname,"a",n[d].stype,n[d].srcfmt);F=t.select();var N=parseInt(a.p.rowNum,10),K=F.length,O=parseInt(a.p.page,10),Y=Math.ceil(K/N),J={};F=F.slice((O-1)*N,O*N);n=t=null;J[a.p.localReader.total]=Y;J[a.p.localReader.page]=
+O;J[a.p.localReader.records]=K;J[a.p.localReader.root]=F;F=null;return J}}},R=function(){a.grid.hDiv.loading=true;if(!a.p.hiddengrid)switch(a.p.loadui){case "enable":b("#load_"+b.jgrid.jqID(a.p.id)).show();break;case "block":b("#lui_"+b.jgrid.jqID(a.p.id)).show();b("#load_"+b.jgrid.jqID(a.p.id)).show()}},$=function(){a.grid.hDiv.loading=false;switch(a.p.loadui){case "enable":b("#load_"+b.jgrid.jqID(a.p.id)).hide();break;case "block":b("#lui_"+b.jgrid.jqID(a.p.id)).hide();b("#load_"+b.jgrid.jqID(a.p.id)).hide()}},
+ja=function(e){if(!a.grid.hDiv.loading){var d=a.p.scroll&&e===false,i={},n,p=a.p.prmNames;if(a.p.page<=0)a.p.page=1;if(p.search!==null)i[p.search]=a.p.search;if(p.nd!==null)i[p.nd]=(new Date).getTime();if(p.rows!==null)i[p.rows]=a.p.rowNum;if(p.page!==null)i[p.page]=a.p.page;if(p.sort!==null)i[p.sort]=a.p.sortname;if(p.order!==null)i[p.order]=a.p.sortorder;if(a.p.rowTotal!==null&&p.totalrows!==null)i[p.totalrows]=a.p.rowTotal;var A=a.p.loadComplete,s=b.isFunction(A);s||(A=null);var E=0;e=e||1;if(e>
+1)if(p.npage!==null){i[p.npage]=e;E=e-1;e=1}else A=function(z){a.p.page++;a.grid.hDiv.loading=false;s&&a.p.loadComplete.call(a,z);ja(e-1)};else p.npage!==null&&delete a.p.postData[p.npage];if(a.p.grouping){b(a).jqGrid("groupingSetup");if(a.p.groupingView.groupDataSorted===true)i[p.sort]=a.p.groupingView.groupField[0]+" "+a.p.groupingView.groupOrder[0]+", "+i[p.sort]}b.extend(a.p.postData,i);var u=!a.p.scroll?1:a.rows.length-1;if(b.isFunction(a.p.datatype))a.p.datatype.call(a,a.p.postData,"load_"+
+a.p.id);else{b.isFunction(a.p.beforeRequest)&&a.p.beforeRequest.call(a);n=a.p.datatype.toLowerCase();switch(n){case "json":case "jsonp":case "xml":case "script":b.ajax(b.extend({url:a.p.url,type:a.p.mtype,dataType:n,data:b.isFunction(a.p.serializeGridData)?a.p.serializeGridData.call(a,a.p.postData):a.p.postData,success:function(z){n==="xml"?V(z,a.grid.bDiv,u,e>1,E):fa(z,a.grid.bDiv,u,e>1,E);A&&A.call(a,z);d&&a.grid.populateVisible();if(a.p.loadonce||a.p.treeGrid)a.p.datatype="local";$()},error:function(z,
+w,t){b.isFunction(a.p.loadError)&&a.p.loadError.call(a,z,w,t);$()},beforeSend:function(z){R();b.isFunction(a.p.loadBeforeSend)&&a.p.loadBeforeSend.call(a,z)}},b.jgrid.ajaxOptions,a.p.ajaxGridOptions));break;case "xmlstring":R();i=b.jgrid.stringToDoc(a.p.datastr);V(i,a.grid.bDiv);s&&a.p.loadComplete.call(a,i);a.p.datatype="local";a.p.datastr=null;$();break;case "jsonstring":R();i=typeof a.p.datastr=="string"?b.jgrid.parse(a.p.datastr):a.p.datastr;fa(i,a.grid.bDiv);s&&a.p.loadComplete.call(a,i);a.p.datatype=
+"local";a.p.datastr=null;$();break;case "local":case "clientside":R();a.p.datatype="local";i=oa();fa(i,a.grid.bDiv,u,e>1,E);A&&A.call(a,i);d&&a.grid.populateVisible();$()}}}};x=function(e,d){var i="",n="<table cellspacing='0' cellpadding='0' border='0' style='table-layout:auto;' class='ui-pg-table'><tbody><tr>",p="",A,s,E,u,z=function(w){var t;if(b.isFunction(a.p.onPaging))t=a.p.onPaging.call(a,w);a.p.selrow=null;if(a.p.multiselect){a.p.selarrrow=[];b("#cb_"+b.jgrid.jqID(a.p.id),a.grid.hDiv).attr("checked",
+false)}a.p.savedRow=[];if(t=="stop")return false;return true};e=e.substr(1);d+="_"+e;A="pg_"+e;s=e+"_left";E=e+"_center";u=e+"_right";b("#"+b.jgrid.jqID(e)).append("<div id='"+A+"' class='ui-pager-control' role='group'><table cellspacing='0' cellpadding='0' border='0' class='ui-pg-table' style='width:100%;table-layout:fixed;height:100%;' role='row'><tbody><tr><td id='"+s+"' align='left'></td><td id='"+E+"' align='center' style='white-space:pre;'></td><td id='"+u+"' align='right'></td></tr></tbody></table></div>").attr("dir",
+"ltr");if(a.p.rowList.length>0){p="<td dir='"+l+"'>";p+="<select class='ui-pg-selbox' role='listbox'>";for(s=0;s<a.p.rowList.length;s++)p+='<option role="option" value="'+a.p.rowList[s]+'"'+(a.p.rowNum==a.p.rowList[s]?' selected="selected"':"")+">"+a.p.rowList[s]+"</option>";p+="</select></td>"}if(l=="rtl")n+=p;if(a.p.pginput===true)i="<td dir='"+l+"'>"+b.jgrid.format(a.p.pgtext||"","<input class='ui-pg-input' type='text' size='2' maxlength='7' value='0' role='textbox'/>","<span id='sp_1_"+b.jgrid.jqID(e)+
+"'></span>")+"</td>";if(a.p.pgbuttons===true){s=["first"+d,"prev"+d,"next"+d,"last"+d];l=="rtl"&&s.reverse();n+="<td id='"+s[0]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-first'></span></td>";n+="<td id='"+s[1]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-prev'></span></td>";n+=i!==""?"<td class='ui-pg-button ui-state-disabled' style='width:4px;'><span class='ui-separator'></span></td>"+i+"<td class='ui-pg-button ui-state-disabled' style='width:4px;'><span class='ui-separator'></span></td>":
+"";n+="<td id='"+s[2]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-next'></span></td>";n+="<td id='"+s[3]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-end'></span></td>"}else if(i!=="")n+=i;if(l=="ltr")n+=p;n+="</tr></tbody></table>";a.p.viewrecords===true&&b("td#"+e+"_"+a.p.recordpos,"#"+A).append("<div dir='"+l+"' style='text-align:"+a.p.recordpos+"' class='ui-paging-info'></div>");b("td#"+e+"_"+a.p.pagerpos,"#"+A).append(n);p=b(".ui-jqgrid").css("font-size")||
+"11px";b(document.body).append("<div id='testpg' class='ui-jqgrid ui-widget ui-widget-content' style='font-size:"+p+";visibility:hidden;' ></div>");n=b(n).clone().appendTo("#testpg").width();b("#testpg").remove();if(n>0){if(i!=="")n+=50;b("td#"+e+"_"+a.p.pagerpos,"#"+A).width(n)}a.p._nvtd=[];a.p._nvtd[0]=n?Math.floor((a.p.width-n)/2):Math.floor(a.p.width/3);a.p._nvtd[1]=0;n=null;b(".ui-pg-selbox","#"+A).bind("change",function(){a.p.page=Math.round(a.p.rowNum*(a.p.page-1)/this.value-0.5)+1;a.p.rowNum=
+this.value;if(d)b(".ui-pg-selbox",a.p.pager).val(this.value);else a.p.toppager&&b(".ui-pg-selbox",a.p.toppager).val(this.value);if(!z("records"))return false;ja();return false});if(a.p.pgbuttons===true){b(".ui-pg-button","#"+A).hover(function(){if(b(this).hasClass("ui-state-disabled"))this.style.cursor="default";else{b(this).addClass("ui-state-hover");this.style.cursor="pointer"}},function(){if(!b(this).hasClass("ui-state-disabled")){b(this).removeClass("ui-state-hover");this.style.cursor="default"}});
+b("#first"+b.jgrid.jqID(d)+", #prev"+b.jgrid.jqID(d)+", #next"+b.jgrid.jqID(d)+", #last"+b.jgrid.jqID(d)).click(function(){var w=M(a.p.page,1),t=M(a.p.lastpage,1),F=false,S=true,N=true,K=true,O=true;if(t===0||t===1)O=K=N=S=false;else if(t>1&&w>=1)if(w===1)N=S=false;else{if(!(w>1&&w<t))if(w===t)O=K=false}else if(t>1&&w===0){O=K=false;w=t-1}if(this.id==="first"+d&&S){a.p.page=1;F=true}if(this.id==="prev"+d&&N){a.p.page=w-1;F=true}if(this.id==="next"+d&&K){a.p.page=w+1;F=true}if(this.id==="last"+d&&
+O){a.p.page=t;F=true}if(F){if(!z(this.id))return false;ja()}return false})}a.p.pginput===true&&b("input.ui-pg-input","#"+A).keypress(function(w){if((w.charCode?w.charCode:w.keyCode?w.keyCode:0)==13){a.p.page=b(this).val()>0?b(this).val():a.p.page;if(!z("user"))return false;ja();return false}return this})};var Ca=function(e,d,i,n){if(a.p.colModel[d].sortable)if(!(a.p.savedRow.length>0)){if(!i){if(a.p.lastsort==d)if(a.p.sortorder=="asc")a.p.sortorder="desc";else{if(a.p.sortorder=="desc")a.p.sortorder=
+"asc"}else a.p.sortorder=a.p.colModel[d].firstsortorder||"asc";a.p.page=1}if(n)if(a.p.lastsort==d&&a.p.sortorder==n&&!i)return;else a.p.sortorder=n;i=b("thead:first",a.grid.hDiv).get(0);b("tr th:eq("+a.p.lastsort+") span.ui-grid-ico-sort",i).addClass("ui-state-disabled");b("tr th:eq("+a.p.lastsort+")",i).attr("aria-selected","false");b("tr th:eq("+d+") span.ui-icon-"+a.p.sortorder,i).removeClass("ui-state-disabled");b("tr th:eq("+d+")",i).attr("aria-selected","true");if(!a.p.viewsortcols[0])if(a.p.lastsort!=
+d){b("tr th:eq("+a.p.lastsort+") span.s-ico",i).hide();b("tr th:eq("+d+") span.s-ico",i).show()}e=e.substring(5+a.p.id.length+1);a.p.sortname=a.p.colModel[d].index||e;i=a.p.sortorder;if(b.isFunction(a.p.onSortCol))if(a.p.onSortCol.call(a,e,d,i)=="stop"){a.p.lastsort=d;return}if(a.p.datatype=="local")a.p.deselectAfterSort&&b(a).jqGrid("resetSelection");else{a.p.selrow=null;a.p.multiselect&&b("#cb_"+b.jgrid.jqID(a.p.id),a.grid.hDiv).attr("checked",false);a.p.selarrrow=[];a.p.savedRow=[]}if(a.p.scroll){i=
+a.grid.bDiv.scrollLeft;C(a.grid.bDiv,true,false);a.grid.hDiv.scrollLeft=i}a.p.subGrid&&a.p.datatype=="local"&&b("td.sgexpanded","#"+b.jgrid.jqID(a.p.id)).each(function(){b(this).trigger("click")});ja();a.p.lastsort=d;if(a.p.sortname!=e&&d)a.p.lastsort=d}},Fa=function(e){var d,i={},n=H?0:a.p.cellLayout;for(d=i[0]=i[1]=i[2]=0;d<=e;d++)if(a.p.colModel[d].hidden===false)i[0]+=a.p.colModel[d].width+n;if(a.p.direction=="rtl")i[0]=a.p.width-i[0];i[0]-=a.grid.bDiv.scrollLeft;if(b(a.grid.cDiv).is(":visible"))i[1]+=
+b(a.grid.cDiv).height()+parseInt(b(a.grid.cDiv).css("padding-top"),10)+parseInt(b(a.grid.cDiv).css("padding-bottom"),10);if(a.p.toolbar[0]===true&&(a.p.toolbar[1]=="top"||a.p.toolbar[1]=="both"))i[1]+=b(a.grid.uDiv).height()+parseInt(b(a.grid.uDiv).css("border-top-width"),10)+parseInt(b(a.grid.uDiv).css("border-bottom-width"),10);if(a.p.toppager)i[1]+=b(a.grid.topDiv).height()+parseInt(b(a.grid.topDiv).css("border-bottom-width"),10);i[2]+=b(a.grid.bDiv).height()+b(a.grid.hDiv).height();return i};
+this.p.id=this.id;if(b.inArray(a.p.multikey,["shiftKey","altKey","ctrlKey"])==-1)a.p.multikey=false;a.p.keyIndex=false;for(k=0;k<a.p.colModel.length;k++){a.p.colModel[k]=b.extend(true,{},a.p.cmTemplate,a.p.colModel[k].template||{},a.p.colModel[k]);if(a.p.keyIndex===false&&a.p.colModel[k].key===true)a.p.keyIndex=k}a.p.sortorder=a.p.sortorder.toLowerCase();if(a.p.grouping===true){a.p.scroll=false;a.p.rownumbers=false;a.p.subGrid=false;a.p.treeGrid=false;a.p.gridview=true}if(this.p.treeGrid===true){try{b(this).jqGrid("setTreeGrid")}catch(Ja){}if(a.p.datatype!=
+"local")a.p.localReader={id:"_id_"}}if(this.p.subGrid)try{b(a).jqGrid("setSubGrid")}catch(Ka){}if(this.p.multiselect){this.p.colNames.unshift("<input role='checkbox' id='cb_"+this.p.id+"' class='cbox' type='checkbox'/>");this.p.colModel.unshift({name:"cb",width:H?a.p.multiselectWidth+a.p.cellLayout:a.p.multiselectWidth,sortable:false,resizable:false,hidedlg:true,search:false,align:"center",fixed:true})}if(this.p.rownumbers){this.p.colNames.unshift("");this.p.colModel.unshift({name:"rn",width:a.p.rownumWidth,
+sortable:false,resizable:false,hidedlg:true,search:false,align:"center",fixed:true})}a.p.xmlReader=b.extend(true,{root:"rows",row:"row",page:"rows>page",total:"rows>total",records:"rows>records",repeatitems:true,cell:"cell",id:"[id]",userdata:"userdata",subgrid:{root:"rows",row:"row",repeatitems:true,cell:"cell"}},a.p.xmlReader);a.p.jsonReader=b.extend(true,{root:"rows",page:"page",total:"total",records:"records",repeatitems:true,cell:"cell",id:"id",userdata:"userdata",subgrid:{root:"rows",repeatitems:true,
+cell:"cell"}},a.p.jsonReader);a.p.localReader=b.extend(true,{root:"rows",page:"page",total:"total",records:"records",repeatitems:false,cell:"cell",id:"id",userdata:"userdata",subgrid:{root:"rows",repeatitems:true,cell:"cell"}},a.p.localReader);if(a.p.scroll){a.p.pgbuttons=false;a.p.pginput=false;a.p.rowList=[]}a.p.data.length&&ca();var da="<thead><tr class='ui-jqgrid-labels' role='rowheader'>",Da,ma,sa,ra,ta,X,Q,na;ma=na="";if(a.p.shrinkToFit===true&&a.p.forceFit===true)for(k=a.p.colModel.length-
+1;k>=0;k--)if(!a.p.colModel[k].hidden){a.p.colModel[k].resizable=false;break}if(a.p.viewsortcols[1]=="horizontal"){na=" ui-i-asc";ma=" ui-i-desc"}Da=y?"class='ui-th-div-ie'":"";na="<span class='s-ico' style='display:none'><span sort='asc' class='ui-grid-ico-sort ui-icon-asc"+na+" ui-state-disabled ui-icon ui-icon-triangle-1-n ui-sort-"+l+"'></span>";na+="<span sort='desc' class='ui-grid-ico-sort ui-icon-desc"+ma+" ui-state-disabled ui-icon ui-icon-triangle-1-s ui-sort-"+l+"'></span></span>";for(k=
+0;k<this.p.colNames.length;k++){ma=a.p.headertitles?' title="'+b.jgrid.stripHtml(a.p.colNames[k])+'"':"";da+="<th id='"+a.p.id+"_"+a.p.colModel[k].name+"' role='columnheader' class='ui-state-default ui-th-column ui-th-"+l+"'"+ma+">";ma=a.p.colModel[k].index||a.p.colModel[k].name;da+="<div id='jqgh_"+a.p.id+"_"+a.p.colModel[k].name+"' "+Da+">"+a.p.colNames[k];a.p.colModel[k].width=a.p.colModel[k].width?parseInt(a.p.colModel[k].width,10):150;if(typeof a.p.colModel[k].title!=="boolean")a.p.colModel[k].title=
+true;if(ma==a.p.sortname)a.p.lastsort=k;da+=na+"</div></th>"}da+="</tr></thead>";na=null;b(this).append(da);b("thead tr:first th",this).hover(function(){b(this).addClass("ui-state-hover")},function(){b(this).removeClass("ui-state-hover")});if(this.p.multiselect){var za=[],ua;b("#cb_"+b.jgrid.jqID(a.p.id),this).bind("click",function(){a.p.selarrrow=[];if(this.checked){b(a.rows).each(function(e){if(e>0)if(!b(this).hasClass("subgrid")&&!b(this).hasClass("jqgroup")&&!b(this).hasClass("ui-state-disabled")){b("#jqg_"+
+b.jgrid.jqID(a.p.id)+"_"+b.jgrid.jqID(this.id)).attr("checked","checked");b(this).addClass("ui-state-highlight").attr("aria-selected","true");a.p.selarrrow.push(this.id);a.p.selrow=this.id}});ua=true;za=[]}else{b(a.rows).each(function(e){if(e>0)if(!b(this).hasClass("subgrid")&&!b(this).hasClass("ui-state-disabled")){b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+b.jgrid.jqID(this.id)).removeAttr("checked");b(this).removeClass("ui-state-highlight").attr("aria-selected","false");za.push(this.id)}});a.p.selrow=
+null;ua=false}if(b.isFunction(a.p.onSelectAll))a.p.onSelectAll.call(a,ua?a.p.selarrrow:za,ua)})}if(a.p.autowidth===true){da=b(L).innerWidth();a.p.width=da>0?da:"nw"}(function(){var e=0,d=H?0:a.p.cellLayout,i=0,n,p=a.p.scrollOffset,A,s=false,E,u=0,z=0,w;b.each(a.p.colModel,function(){if(typeof this.hidden==="undefined")this.hidden=false;this.widthOrg=A=M(this.width,0);if(this.hidden===false){e+=A+d;if(this.fixed)u+=A+d;else i++;z++}});if(isNaN(a.p.width))a.p.width=g.width=e;else g.width=a.p.width;
+a.p.tblwidth=e;if(a.p.shrinkToFit===false&&a.p.forceFit===true)a.p.forceFit=false;if(a.p.shrinkToFit===true&&i>0){E=g.width-d*i-u;if(!isNaN(a.p.height)){E-=p;s=true}e=0;b.each(a.p.colModel,function(t){if(this.hidden===false&&!this.fixed){this.width=A=Math.round(E*this.width/(a.p.tblwidth-d*i-u));e+=A;n=t}});w=0;if(s){if(g.width-u-(e+d*i)!==p)w=g.width-u-(e+d*i)-p}else if(!s&&Math.abs(g.width-u-(e+d*i))!==1)w=g.width-u-(e+d*i);a.p.colModel[n].width+=w;a.p.tblwidth=e+w+d*i+u;if(a.p.tblwidth>a.p.width){a.p.colModel[n].width-=
+a.p.tblwidth-parseInt(a.p.width,10);a.p.tblwidth=a.p.width}}})();b(L).css("width",g.width+"px").append("<div class='ui-jqgrid-resize-mark' id='rs_m"+a.p.id+"'> </div>");b(q).css("width",g.width+"px");da=b("thead:first",a).get(0);var va="";if(a.p.footerrow)va+="<table role='grid' style='width:"+a.p.tblwidth+"px' class='ui-jqgrid-ftable' cellspacing='0' cellpadding='0' border='0'><tbody><tr role='row' class='ui-widget-content footrow footrow-"+l+"'>";q=b("tr:first",da);var wa="<tr class='jqgfirstrow' role='row' style='height:auto'>";
+a.p.disableClick=false;b("th",q).each(function(e){sa=a.p.colModel[e].width;if(typeof a.p.colModel[e].resizable==="undefined")a.p.colModel[e].resizable=true;if(a.p.colModel[e].resizable){ra=document.createElement("span");b(ra).html(" ").addClass("ui-jqgrid-resize ui-jqgrid-resize-"+l);b.browser.opera||b(ra).css("cursor","col-resize");b(this).addClass(a.p.resizeclass)}else ra="";b(this).css("width",sa+"px").prepend(ra);var d="";if(a.p.colModel[e].hidden){b(this).css("display","none");d="display:none;"}wa+=
+"<td role='gridcell' style='height:0px;width:"+sa+"px;"+d+"'></td>";g.headers[e]={width:sa,el:this};ta=a.p.colModel[e].sortable;if(typeof ta!=="boolean")ta=a.p.colModel[e].sortable=true;d=a.p.colModel[e].name;d=="cb"||d=="subgrid"||d=="rn"||a.p.viewsortcols[2]&&b("div",this).addClass("ui-jqgrid-sortable");if(ta)if(a.p.viewsortcols[0]){b("div span.s-ico",this).show();e==a.p.lastsort&&b("div span.ui-icon-"+a.p.sortorder,this).removeClass("ui-state-disabled")}else if(e==a.p.lastsort){b("div span.s-ico",
+this).show();b("div span.ui-icon-"+a.p.sortorder,this).removeClass("ui-state-disabled")}if(a.p.footerrow)va+="<td role='gridcell' "+P(e,0,"",null,"",false)+"> </td>"}).mousedown(function(e){if(b(e.target).closest("th>span.ui-jqgrid-resize").length==1){var d=b.jgrid.getCellIndex(this);if(a.p.forceFit===true){var i=a.p,n=d,p;for(p=d+1;p<a.p.colModel.length;p++)if(a.p.colModel[p].hidden!==true){n=p;break}i.nv=n-d}g.dragStart(d,e,Fa(d));return false}}).click(function(e){if(a.p.disableClick)return a.p.disableClick=
+false;var d="th>div.ui-jqgrid-sortable",i,n;a.p.viewsortcols[2]||(d="th>div>span>span.ui-grid-ico-sort");e=b(e.target).closest(d);if(e.length==1){d=b.jgrid.getCellIndex(this);if(!a.p.viewsortcols[2]){i=true;n=e.attr("sort")}Ca(b("div",this)[0].id,d,i,n);return false}});if(a.p.sortable&&b.fn.sortable)try{b(a).jqGrid("sortableColumns",q)}catch(La){}if(a.p.footerrow)va+="</tr></tbody></table>";wa+="</tr>";this.appendChild(document.createElement("tbody"));b(this).addClass("ui-jqgrid-btable").append(wa);
+wa=null;q=b("<table class='ui-jqgrid-htable' style='width:"+a.p.tblwidth+"px' role='grid' aria-labelledby='gbox_"+this.id+"' cellspacing='0' cellpadding='0' border='0'></table>").append(da);var ea=a.p.caption&&a.p.hiddengrid===true?true:false;k=b("<div class='ui-jqgrid-hbox"+(l=="rtl"?"-rtl":"")+"'></div>");da=null;g.hDiv=document.createElement("div");b(g.hDiv).css({width:g.width+"px"}).addClass("ui-state-default ui-jqgrid-hdiv").append(k);b(k).append(q);q=null;ea&&b(g.hDiv).hide();if(a.p.pager){if(typeof a.p.pager==
+"string"){if(a.p.pager.substr(0,1)!="#")a.p.pager="#"+a.p.pager}else a.p.pager="#"+b(a.p.pager).attr("id");b(a.p.pager).css({width:g.width+"px"}).appendTo(L).addClass("ui-state-default ui-jqgrid-pager ui-corner-bottom");ea&&b(a.p.pager).hide();x(a.p.pager,"")}a.p.cellEdit===false&&a.p.hoverrows===true&&b(a).bind("mouseover",function(e){Q=b(e.target).closest("tr.jqgrow");b(Q).attr("class")!=="subgrid"&&b(Q).addClass("ui-state-hover")}).bind("mouseout",function(e){Q=b(e.target).closest("tr.jqgrow");
+b(Q).removeClass("ui-state-hover")});var ka,la;b(a).before(g.hDiv).click(function(e){X=e.target;Q=b(X,a.rows).closest("tr.jqgrow");if(b(Q).length===0||Q[0].className.indexOf("ui-state-disabled")>-1)return this;var d=b(X).hasClass("cbox"),i=true;if(b.isFunction(a.p.beforeSelectRow))i=a.p.beforeSelectRow.call(a,Q[0].id,e);if(X.tagName=="A"||(X.tagName=="INPUT"||X.tagName=="TEXTAREA"||X.tagName=="OPTION"||X.tagName=="SELECT")&&!d)return this;if(i===true){if(a.p.cellEdit===true)if(a.p.multiselect&&d)b(a).jqGrid("setSelection",
+Q[0].id,true);else{ka=Q[0].rowIndex;la=b.jgrid.getCellIndex(X);try{b(a).jqGrid("editCell",ka,la,true)}catch(n){}}else if(a.p.multikey)if(e[a.p.multikey])b(a).jqGrid("setSelection",Q[0].id,true);else{if(a.p.multiselect&&d){d=b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+Q[0].id).attr("checked");b("#jqg_"+b.jgrid.jqID(a.p.id)+"_"+Q[0].id).attr("checked",!d)}}else{if(a.p.multiselect&&a.p.multiboxonly)if(!d){b(a.p.selarrrow).each(function(p,A){var s=a.rows.namedItem(A);b(s).removeClass("ui-state-highlight");b("#jqg_"+
+b.jgrid.jqID(a.p.id)+"_"+b.jgrid.jqID(A)).attr("checked",false)});a.p.selarrrow=[];b("#cb_"+b.jgrid.jqID(a.p.id),a.grid.hDiv).attr("checked",false)}b(a).jqGrid("setSelection",Q[0].id,true)}if(b.isFunction(a.p.onCellSelect)){ka=Q[0].id;la=b.jgrid.getCellIndex(X);a.p.onCellSelect.call(a,ka,la,b(X).html(),e)}}return this}).bind("reloadGrid",function(e,d){if(a.p.treeGrid===true)a.p.datatype=a.p.treedatatype;d&&d.current&&a.grid.selectionPreserver(a);if(a.p.datatype=="local"){b(a).jqGrid("resetSelection");
+a.p.data.length&&ca()}else if(!a.p.treeGrid){a.p.selrow=null;if(a.p.multiselect){a.p.selarrrow=[];b("#cb_"+b.jgrid.jqID(a.p.id),a.grid.hDiv).attr("checked",false)}a.p.savedRow=[]}a.p.scroll&&C(a.grid.bDiv,true,false);if(d&&d.page){var i=d.page;if(i>a.p.lastpage)i=a.p.lastpage;if(i<1)i=1;a.p.page=i;a.grid.bDiv.scrollTop=a.grid.prevRowHeight?(i-1)*a.grid.prevRowHeight*a.p.rowNum:0}if(a.grid.prevRowHeight&&a.p.scroll){delete a.p.lastpage;a.grid.populateVisible()}else a.grid.populate();return false});
+b.isFunction(this.p.ondblClickRow)&&b(this).dblclick(function(e){X=e.target;Q=b(X,a.rows).closest("tr.jqgrow");if(b(Q).length===0)return false;ka=Q[0].rowIndex;la=b.jgrid.getCellIndex(X);a.p.ondblClickRow.call(a,b(Q).attr("id"),ka,la,e);return false});b.isFunction(this.p.onRightClickRow)&&b(this).bind("contextmenu",function(e){X=e.target;Q=b(X,a.rows).closest("tr.jqgrow");if(b(Q).length===0)return false;a.p.multiselect||b(a).jqGrid("setSelection",Q[0].id,true);ka=Q[0].rowIndex;la=b.jgrid.getCellIndex(X);
+a.p.onRightClickRow.call(a,b(Q).attr("id"),ka,la,e);return false});g.bDiv=document.createElement("div");if(y)if(String(a.p.height).toLowerCase()==="auto")a.p.height="100%";b(g.bDiv).append(b('<div style="position:relative;'+(y&&b.browser.version<8?"height:0.01%;":"")+'"></div>').append("<div></div>").append(this)).addClass("ui-jqgrid-bdiv").css({height:a.p.height+(isNaN(a.p.height)?"":"px"),width:g.width+"px"}).scroll(g.scrollGrid);b("table:first",g.bDiv).css({width:a.p.tblwidth+"px"});if(y){b("tbody",
+this).size()==2&&b("tbody:gt(0)",this).remove();a.p.multikey&&b(g.bDiv).bind("selectstart",function(){return false})}else a.p.multikey&&b(g.bDiv).bind("mousedown",function(){return false});ea&&b(g.bDiv).hide();g.cDiv=document.createElement("div");var Aa=a.p.hidegrid===true?b("<a role='link' href='javascript:void(0)'/>").addClass("ui-jqgrid-titlebar-close HeaderButton").hover(function(){Aa.addClass("ui-state-hover")},function(){Aa.removeClass("ui-state-hover")}).append("<span class='ui-icon ui-icon-circle-triangle-n'></span>").css(l==
+"rtl"?"left":"right","0px"):"";b(g.cDiv).append(Aa).append("<span class='ui-jqgrid-title"+(l=="rtl"?"-rtl":"")+"'>"+a.p.caption+"</span>").addClass("ui-jqgrid-titlebar ui-widget-header ui-corner-top ui-helper-clearfix");b(g.cDiv).insertBefore(g.hDiv);if(a.p.toolbar[0]){g.uDiv=document.createElement("div");if(a.p.toolbar[1]=="top")b(g.uDiv).insertBefore(g.hDiv);else a.p.toolbar[1]=="bottom"&&b(g.uDiv).insertAfter(g.hDiv);if(a.p.toolbar[1]=="both"){g.ubDiv=document.createElement("div");b(g.uDiv).insertBefore(g.hDiv).addClass("ui-userdata ui-state-default").attr("id",
+"t_"+this.id);b(g.ubDiv).insertAfter(g.hDiv).addClass("ui-userdata ui-state-default").attr("id","tb_"+this.id);ea&&b(g.ubDiv).hide()}else b(g.uDiv).width(g.width).addClass("ui-userdata ui-state-default").attr("id","t_"+this.id);ea&&b(g.uDiv).hide()}if(a.p.toppager){a.p.toppager=b.jgrid.jqID(a.p.id)+"_toppager";g.topDiv=b("<div id='"+a.p.toppager+"'></div>")[0];a.p.toppager="#"+a.p.toppager;b(g.topDiv).insertBefore(g.hDiv).addClass("ui-state-default ui-jqgrid-toppager").width(g.width);x(a.p.toppager,
+"_t")}if(a.p.footerrow){g.sDiv=b("<div class='ui-jqgrid-sdiv'></div>")[0];k=b("<div class='ui-jqgrid-hbox"+(l=="rtl"?"-rtl":"")+"'></div>");b(g.sDiv).append(k).insertAfter(g.hDiv).width(g.width);b(k).append(va);g.footers=b(".ui-jqgrid-ftable",g.sDiv)[0].rows[0].cells;if(a.p.rownumbers)g.footers[0].className="ui-state-default jqgrid-rownum";ea&&b(g.sDiv).hide()}k=null;if(a.p.caption){var Ga=a.p.datatype;if(a.p.hidegrid===true){b(".ui-jqgrid-titlebar-close",g.cDiv).click(function(e){var d=b.isFunction(a.p.onHeaderClick),
+i=".ui-jqgrid-bdiv, .ui-jqgrid-hdiv, .ui-jqgrid-pager, .ui-jqgrid-sdiv",n,p=this;if(a.p.toolbar[0]===true){if(a.p.toolbar[1]=="both")i+=", #"+b(g.ubDiv).attr("id");i+=", #"+b(g.uDiv).attr("id")}n=b(i,"#gview_"+b.jgrid.jqID(a.p.id)).length;if(a.p.gridstate=="visible")b(i,"#gbox_"+b.jgrid.jqID(a.p.id)).slideUp("fast",function(){n--;if(n===0){b("span",p).removeClass("ui-icon-circle-triangle-n").addClass("ui-icon-circle-triangle-s");a.p.gridstate="hidden";b("#gbox_"+b.jgrid.jqID(a.p.id)).hasClass("ui-resizable")&&
+b(".ui-resizable-handle","#gbox_"+b.jgrid.jqID(a.p.id)).hide();if(d)ea||a.p.onHeaderClick.call(a,a.p.gridstate,e)}});else a.p.gridstate=="hidden"&&b(i,"#gbox_"+b.jgrid.jqID(a.p.id)).slideDown("fast",function(){n--;if(n===0){b("span",p).removeClass("ui-icon-circle-triangle-s").addClass("ui-icon-circle-triangle-n");if(ea){a.p.datatype=Ga;ja();ea=false}a.p.gridstate="visible";b("#gbox_"+b.jgrid.jqID(a.p.id)).hasClass("ui-resizable")&&b(".ui-resizable-handle","#gbox_"+b.jgrid.jqID(a.p.id)).show();if(d)ea||
+a.p.onHeaderClick.call(a,a.p.gridstate,e)}});return false});if(ea){a.p.datatype="local";b(".ui-jqgrid-titlebar-close",g.cDiv).trigger("click")}}}else b(g.cDiv).hide();b(g.hDiv).after(g.bDiv).mousemove(function(e){if(g.resizing){g.dragMove(e);return false}});b(".ui-jqgrid-labels",g.hDiv).bind("selectstart",function(){return false});b(document).mouseup(function(){if(g.resizing){g.dragEnd();return false}return true});a.formatCol=P;a.sortData=Ca;a.updatepager=function(e,d){var i,n,p,A,s,E,u,z="",w=a.p.pager?
+"_"+b.jgrid.jqID(a.p.pager.substr(1)):"",t=a.p.toppager?"_"+a.p.toppager.substr(1):"";p=parseInt(a.p.page,10)-1;if(p<0)p=0;p*=parseInt(a.p.rowNum,10);s=p+a.p.reccount;if(a.p.scroll){i=b("tbody:first > tr:gt(0)",a.grid.bDiv);p=s-i.length;a.p.reccount=i.length;if(n=i.outerHeight()||a.grid.prevRowHeight){i=p*n;n*=parseInt(a.p.records,10);b(">div:first",a.grid.bDiv).css({height:n}).children("div:first").css({height:i,display:i?"":"none"})}a.grid.bDiv.scrollLeft=a.grid.hDiv.scrollLeft}z=a.p.pager?a.p.pager:
+"";z+=a.p.toppager?z?","+a.p.toppager:a.p.toppager:"";if(z){u=b.jgrid.formatter.integer||{};i=M(a.p.page);n=M(a.p.lastpage);b(".selbox",z).attr("disabled",false);if(a.p.pginput===true){b(".ui-pg-input",z).val(a.p.page);A=a.p.toppager?"#sp_1"+w+",#sp_1"+t:"#sp_1"+w;b(A).html(b.fmatter?b.fmatter.util.NumberFormat(a.p.lastpage,u):a.p.lastpage)}if(a.p.viewrecords)if(a.p.reccount===0)b(".ui-paging-info",z).html(a.p.emptyrecords);else{A=p+1;E=a.p.records;if(b.fmatter){A=b.fmatter.util.NumberFormat(A,u);
+s=b.fmatter.util.NumberFormat(s,u);E=b.fmatter.util.NumberFormat(E,u)}b(".ui-paging-info",z).html(b.jgrid.format(a.p.recordtext,A,s,E))}if(a.p.pgbuttons===true){if(i<=0)i=n=0;if(i==1||i===0){b("#first"+w+", #prev"+w).addClass("ui-state-disabled").removeClass("ui-state-hover");a.p.toppager&&b("#first_t"+t+", #prev_t"+t).addClass("ui-state-disabled").removeClass("ui-state-hover")}else{b("#first"+w+", #prev"+w).removeClass("ui-state-disabled");a.p.toppager&&b("#first_t"+t+", #prev_t"+t).removeClass("ui-state-disabled")}if(i==
+n||i===0){b("#next"+w+", #last"+w).addClass("ui-state-disabled").removeClass("ui-state-hover");a.p.toppager&&b("#next_t"+t+", #last_t"+t).addClass("ui-state-disabled").removeClass("ui-state-hover")}else{b("#next"+w+", #last"+w).removeClass("ui-state-disabled");a.p.toppager&&b("#next_t"+t+", #last_t"+t).removeClass("ui-state-disabled")}}}e===true&&a.p.rownumbers===true&&b("td.jqgrid-rownum",a.rows).each(function(F){b(this).html(p+1+F)});d&&a.p.jqgdnd&&b(a).jqGrid("gridDnD","updateDnD");b.isFunction(a.p.gridComplete)&&
+a.p.gridComplete.call(a)};a.refreshIndex=ca;a.formatter=function(e,d,i,n,p){return o(e,d,i,n,p)};b.extend(g,{populate:ja,emptyRows:C});this.grid=g;a.addXmlData=function(e){V(e,a.grid.bDiv)};a.addJSONData=function(e){fa(e,a.grid.bDiv)};this.grid.cols=this.rows[0].cells;ja();a.p.hiddengrid=false;b(window).unload(function(){a=null})}}}})};b.jgrid.extend({getGridParam:function(f){var j=this[0];if(j&&j.grid)return f?typeof j.p[f]!="undefined"?j.p[f]:null:j.p},setGridParam:function(f){return this.each(function(){this.grid&&
+typeof f==="object"&&b.extend(true,this.p,f)})},getDataIDs:function(){var f=[],j=0,h,c=0;this.each(function(){if((h=this.rows.length)&&h>0)for(;j<h;){if(b(this.rows[j]).hasClass("jqgrow")){f[c]=this.rows[j].id;c++}j++}});return f},setSelection:function(f,j){return this.each(function(){function h(a){var q=b(c.grid.bDiv)[0].clientHeight,x=b(c.grid.bDiv)[0].scrollTop,y=c.rows[a].offsetTop;a=c.rows[a].clientHeight;if(y+a>=q+x)b(c.grid.bDiv)[0].scrollTop=y-(q+x)+a+x;else if(y<q+x)if(y<x)b(c.grid.bDiv)[0].scrollTop=
+y}var c=this,g,k,l;if(f!==undefined){j=j===false?false:true;k=c.rows.namedItem(f+"");if(!(!k||k.className.indexOf("ui-state-disabled")>-1)){if(c.p.scrollrows===true){g=c.rows.namedItem(f).rowIndex;g>=0&&h(g)}if(c.p.multiselect){c.p.selrow=k.id;l=b.inArray(c.p.selrow,c.p.selarrrow);if(l===-1){k.className!=="ui-subgrid"&&b(k).addClass("ui-state-highlight").attr("aria-selected","true");g=true;b("#jqg_"+b.jgrid.jqID(c.p.id)+"_"+b.jgrid.jqID(c.p.selrow)).attr("checked",g);c.p.selarrrow.push(c.p.selrow)}else{k.className!==
+"ui-subgrid"&&b(k).removeClass("ui-state-highlight").attr("aria-selected","false");g=false;b("#jqg_"+b.jgrid.jqID(c.p.id)+"_"+b.jgrid.jqID(c.p.selrow)).attr("checked",g);c.p.selarrrow.splice(l,1);l=c.p.selarrrow[0];c.p.selrow=l===undefined?null:l}c.p.onSelectRow&&j&&c.p.onSelectRow.call(c,k.id,g)}else if(k.className!=="ui-subgrid"){if(c.p.selrow!=k.id){b(c.rows.namedItem(c.p.selrow)).removeClass("ui-state-highlight").attr({"aria-selected":"false",tabindex:"-1"});b(k).addClass("ui-state-highlight").attr({"aria-selected":true,
+tabindex:"0"});g=true}else g=false;c.p.selrow=k.id;c.p.onSelectRow&&j&&c.p.onSelectRow.call(c,k.id,g)}}}})},resetSelection:function(f){return this.each(function(){var j=this,h,c;if(typeof f!=="undefined"){c=f===j.p.selrow?j.p.selrow:f;b("#"+b.jgrid.jqID(j.p.id)+" tbody:first tr#"+b.jgrid.jqID(c)).removeClass("ui-state-highlight").attr("aria-selected","false");if(j.p.multiselect){b("#jqg_"+b.jgrid.jqID(j.p.id)+"_"+b.jgrid.jqID(c)).attr("checked",false);b("#cb_"+b.jgrid.jqID(j.p.id)).attr("checked",
+false)}c=null}else if(j.p.multiselect){b(j.p.selarrrow).each(function(g,k){h=j.rows.namedItem(k);b(h).removeClass("ui-state-highlight").attr("aria-selected","false");b("#jqg_"+b.jgrid.jqID(j.p.id)+"_"+b.jgrid.jqID(k)).attr("checked",false)});b("#cb_"+b.jgrid.jqID(j.p.id)).attr("checked",false);j.p.selarrrow=[]}else if(j.p.selrow){b("#"+b.jgrid.jqID(j.p.id)+" tbody:first tr#"+b.jgrid.jqID(j.p.selrow)).removeClass("ui-state-highlight").attr("aria-selected","false");j.p.selrow=null}j.p.savedRow=[]})},
+getRowData:function(f){var j={},h,c=false,g,k=0;this.each(function(){var l=this,a,q;if(typeof f=="undefined"){c=true;h=[];g=l.rows.length}else{q=l.rows.namedItem(f);if(!q)return j;g=2}for(;k<g;){if(c)q=l.rows[k];if(b(q).hasClass("jqgrow")){b("td",q).each(function(x){a=l.p.colModel[x].name;if(a!=="cb"&&a!=="subgrid"&&a!=="rn")if(l.p.treeGrid===true&&a==l.p.ExpandColumn)j[a]=b.jgrid.htmlDecode(b("span:first",this).html());else try{j[a]=b.unformat(this,{rowId:q.id,colModel:l.p.colModel[x]},x)}catch(y){j[a]=
+b.jgrid.htmlDecode(b(this).html())}});if(c){h.push(j);j={}}}k++}});return h?h:j},delRowData:function(f){var j=false,h,c;this.each(function(){if(h=this.rows.namedItem(f)){b(h).remove();this.p.records--;this.p.reccount--;this.updatepager(true,false);j=true;if(this.p.multiselect){c=b.inArray(f,this.p.selarrrow);c!=-1&&this.p.selarrrow.splice(c,1)}if(f==this.p.selrow)this.p.selrow=null}else return false;if(this.p.datatype=="local"){var g=this.p._index[f];if(typeof g!="undefined"){this.p.data.splice(g,
+1);this.refreshIndex()}}if(this.p.altRows===true&&j){var k=this.p.altclass;b(this.rows).each(function(l){l%2==1?b(this).addClass(k):b(this).removeClass(k)})}});return j},setRowData:function(f,j,h){var c,g=true,k;this.each(function(){if(!this.grid)return false;var l=this,a,q,x=typeof h,y={};q=l.rows.namedItem(f);if(!q)return false;if(j)try{b(this.p.colModel).each(function(P){c=this.name;if(j[c]!==undefined){y[c]=this.formatter&&typeof this.formatter==="string"&&this.formatter=="date"?b.unformat.date(j[c],
+this):j[c];a=l.formatter(f,j[c],P,j,"edit");k=this.title?{title:b.jgrid.stripHtml(a)}:{};l.p.treeGrid===true&&c==l.p.ExpandColumn?b("td:eq("+P+") > span:first",q).html(a).attr(k):b("td:eq("+P+")",q).html(a).attr(k)}});if(l.p.datatype=="local"){var H=l.p._index[f];if(l.p.treeGrid)for(var L in l.p.treeReader)y.hasOwnProperty(l.p.treeReader[L])&&delete y[l.p.treeReader[L]];if(typeof H!="undefined")l.p.data[H]=b.extend(true,l.p.data[H],y);y=null}}catch(M){g=false}if(g)if(x==="string")b(q).addClass(h);
+else x==="object"&&b(q).css(h)});return g},addRowData:function(f,j,h,c){h||(h="last");var g=false,k,l,a,q,x,y,H,L,M="",P,U,o,m,r;if(j){if(b.isArray(j)){P=true;h="last";U=f}else{j=[j];P=false}this.each(function(){var D=j.length;x=this.p.rownumbers===true?1:0;a=this.p.multiselect===true?1:0;q=this.p.subGrid===true?1:0;if(!P)if(typeof f!="undefined")f+="";else{f=b.jgrid.randId();if(this.p.keyIndex!==false){U=this.p.colModel[this.p.keyIndex+a+q+x].name;if(typeof j[0][U]!="undefined")f=j[0][U]}}o=this.p.altclass;
+for(var T=0,I="",C={},ca=b.isFunction(this.p.afterInsertRow)?true:false;T<D;){m=j[T];l="";if(P){try{f=m[U]}catch(V){f=b.jgrid.randId()}I=this.p.altRows===true?(this.rows.length-1)%2===0?o:"":""}if(x){M=this.formatCol(0,1,"",null,f,true);l+='<td role="gridcell" aria-describedby="'+this.p.id+'_rn" class="ui-state-default jqgrid-rownum" '+M+">0</td>"}if(a){L='<input role="checkbox" type="checkbox" id="jqg_'+this.p.id+"_"+f+'" class="cbox"/>';M=this.formatCol(x,1,"",null,f,true);l+='<td role="gridcell" aria-describedby="'+
+this.p.id+'_cb" '+M+">"+L+"</td>"}if(q)l+=b(this).jqGrid("addSubGridCell",a+x,1);for(H=a+q+x;H<this.p.colModel.length;H++){r=this.p.colModel[H];k=r.name;C[k]=r.formatter&&typeof r.formatter==="string"&&r.formatter=="date"?b.unformat.date(m[k],r):m[k];L=this.formatter(f,b.jgrid.getAccessor(m,k),H,m,"edit");M=this.formatCol(H,1,L,f,m,true);l+='<td role="gridcell" aria-describedby="'+this.p.id+"_"+k+'" '+M+">"+L+"</td>"}l='<tr id="'+f+'" role="row" tabindex="-1" class="ui-widget-content jqgrow ui-row-'+
+this.p.direction+" "+I+'">'+l+"</tr>";if(this.rows.length===0)b("table:first",this.grid.bDiv).append(l);else switch(h){case "last":b(this.rows[this.rows.length-1]).after(l);y=this.rows.length-1;break;case "first":b(this.rows[0]).after(l);y=1;break;case "after":if(y=this.rows.namedItem(c))b(this.rows[y.rowIndex+1]).hasClass("ui-subgrid")?b(this.rows[y.rowIndex+1]).after(l):b(y).after(l);y++;break;case "before":if(y=this.rows.namedItem(c)){b(y).before(l);y=y.rowIndex}y--}this.p.subGrid===true&&b(this).jqGrid("addSubGrid",
+a+x,y);this.p.records++;this.p.reccount++;ca&&this.p.afterInsertRow.call(this,f,m,m);T++;if(this.p.datatype=="local"){C[this.p.localReader.id]=f;this.p._index[f]=this.p.data.length;this.p.data.push(C);C={}}}if(this.p.altRows===true&&!P)if(h=="last")(this.rows.length-1)%2==1&&b(this.rows[this.rows.length-1]).addClass(o);else b(this.rows).each(function(fa){fa%2==1?b(this).addClass(o):b(this).removeClass(o)});this.updatepager(true,true);g=true})}return g},footerData:function(f,j,h){function c(q){for(var x in q)if(q.hasOwnProperty(x))return false;
+return true}var g,k=false,l={},a;if(typeof f=="undefined")f="get";if(typeof h!="boolean")h=true;f=f.toLowerCase();this.each(function(){var q=this,x;if(!q.grid||!q.p.footerrow)return false;if(f=="set")if(c(j))return false;k=true;b(this.p.colModel).each(function(y){g=this.name;if(f=="set"){if(j[g]!==undefined){x=h?q.formatter("",j[g],y,j,"edit"):j[g];a=this.title?{title:b.jgrid.stripHtml(x)}:{};b("tr.footrow td:eq("+y+")",q.grid.sDiv).html(x).attr(a);k=true}}else if(f=="get")l[g]=b("tr.footrow td:eq("+
+y+")",q.grid.sDiv).html()})});return f=="get"?l:k},showHideCol:function(f,j){return this.each(function(){var h=this,c=false,g=b.browser.webkit||b.browser.safari?0:h.p.cellLayout,k;if(h.grid){if(typeof f==="string")f=[f];j=j!="none"?"":"none";var l=j===""?true:false;b(this.p.colModel).each(function(a){if(b.inArray(this.name,f)!==-1&&this.hidden===l){b("tr",h.grid.hDiv).each(function(){b(this).children("th:eq("+a+")").css("display",j)});b(h.rows).each(function(){b(this).children("td:eq("+a+")").css("display",
+j)});h.p.footerrow&&b("tr.footrow td:eq("+a+")",h.grid.sDiv).css("display",j);k=this.widthOrg?this.widthOrg:parseInt(this.width,10);if(j==="none")h.p.tblwidth-=k+g;else h.p.tblwidth+=k+g;this.hidden=!l;c=true}});if(c===true)if(h.p.shrinkToFit===false)b(h).jqGrid("setGridWidth",h.grid.width);else h.grid.width!==h.p.tblwidth&&b(h).jqGrid("setGridWidth",h.p.tblwidth)}})},hideCol:function(f){return this.each(function(){b(this).jqGrid("showHideCol",f,"none")})},showCol:function(f){return this.each(function(){b(this).jqGrid("showHideCol",
+f,"")})},remapColumns:function(f,j,h){function c(l){var a;a=l.length?b.makeArray(l):b.extend({},l);b.each(f,function(q){l[q]=a[this]})}function g(l,a){b(">tr"+(a||""),l).each(function(){var q=this,x=b.makeArray(q.cells);b.each(f,function(){var y=x[this];y&&q.appendChild(y)})})}var k=this.get(0);c(k.p.colModel);c(k.p.colNames);c(k.grid.headers);g(b("thead:first",k.grid.hDiv),h&&":not(.ui-jqgrid-labels)");j&&g(b("#"+b.jgrid.jqID(k.p.id)+" tbody:first"),".jqgfirstrow, tr.jqgrow, tr.jqfoot");k.p.footerrow&&
+g(b("tbody:first",k.grid.sDiv));if(k.p.remapColumns)if(k.p.remapColumns.length)c(k.p.remapColumns);else k.p.remapColumns=b.makeArray(f);k.p.lastsort=b.inArray(k.p.lastsort,f);if(k.p.treeGrid)k.p.expColInd=b.inArray(k.p.expColInd,f)},setGridWidth:function(f,j){return this.each(function(){if(this.grid){var h=this,c,g=0,k=b.browser.webkit||b.browser.safari?0:h.p.cellLayout,l,a=0,q=false,x=h.p.scrollOffset,y,H=0,L=0,M;if(typeof j!="boolean")j=h.p.shrinkToFit;if(!isNaN(f)){f=parseInt(f,10);h.grid.width=
+h.p.width=f;b("#gbox_"+b.jgrid.jqID(h.p.id)).css("width",f+"px");b("#gview_"+b.jgrid.jqID(h.p.id)).css("width",f+"px");b(h.grid.bDiv).css("width",f+"px");b(h.grid.hDiv).css("width",f+"px");h.p.pager&&b(h.p.pager).css("width",f+"px");h.p.toppager&&b(h.p.toppager).css("width",f+"px");if(h.p.toolbar[0]===true){b(h.grid.uDiv).css("width",f+"px");h.p.toolbar[1]=="both"&&b(h.grid.ubDiv).css("width",f+"px")}h.p.footerrow&&b(h.grid.sDiv).css("width",f+"px");if(j===false&&h.p.forceFit===true)h.p.forceFit=
+false;if(j===true){b.each(h.p.colModel,function(){if(this.hidden===false){c=this.widthOrg?this.widthOrg:parseInt(this.width,10);g+=c+k;if(this.fixed)H+=c+k;else a++;L++}});if(a===0)return;h.p.tblwidth=g;y=f-k*a-H;if(!isNaN(h.p.height))if(b(h.grid.bDiv)[0].clientHeight<b(h.grid.bDiv)[0].scrollHeight||h.rows.length===1){q=true;y-=x}g=0;var P=h.grid.cols.length>0;b.each(h.p.colModel,function(U){if(this.hidden===false&&!this.fixed){c=this.widthOrg?this.widthOrg:parseInt(this.width,10);c=Math.round(y*
+c/(h.p.tblwidth-k*a-H));if(!(c<0)){this.width=c;g+=c;h.grid.headers[U].width=c;h.grid.headers[U].el.style.width=c+"px";if(h.p.footerrow)h.grid.footers[U].style.width=c+"px";if(P)h.grid.cols[U].style.width=c+"px";l=U}}});M=0;if(q){if(f-H-(g+k*a)!==x)M=f-H-(g+k*a)-x}else if(Math.abs(f-H-(g+k*a))!==1)M=f-H-(g+k*a);h.p.colModel[l].width+=M;h.p.tblwidth=g+M+k*a+H;if(h.p.tblwidth>f){q=h.p.tblwidth-parseInt(f,10);h.p.tblwidth=f;c=h.p.colModel[l].width-=q}else c=h.p.colModel[l].width;h.grid.headers[l].width=
+c;h.grid.headers[l].el.style.width=c+"px";if(P)h.grid.cols[l].style.width=c+"px";if(h.p.footerrow)h.grid.footers[l].style.width=c+"px"}if(h.p.tblwidth){b("table:first",h.grid.bDiv).css("width",h.p.tblwidth+"px");b("table:first",h.grid.hDiv).css("width",h.p.tblwidth+"px");h.grid.hDiv.scrollLeft=h.grid.bDiv.scrollLeft;h.p.footerrow&&b("table:first",h.grid.sDiv).css("width",h.p.tblwidth+"px")}}}})},setGridHeight:function(f){return this.each(function(){if(this.grid){b(this.grid.bDiv).css({height:f+(isNaN(f)?
+"":"px")});this.p.height=f;this.p.scroll&&this.grid.populateVisible()}})},setCaption:function(f){return this.each(function(){this.p.caption=f;b("span.ui-jqgrid-title",this.grid.cDiv).html(f);b(this.grid.cDiv).show()})},setLabel:function(f,j,h,c){return this.each(function(){var g=-1;if(this.grid)if(typeof f!="undefined"){b(this.p.colModel).each(function(a){if(this.name==f){g=a;return false}});if(g>=0){var k=b("tr.ui-jqgrid-labels th:eq("+g+")",this.grid.hDiv);if(j){var l=b(".s-ico",k);b("[id^=jqgh_]",
+k).empty().html(j).append(l);this.p.colNames[g]=j}if(h)typeof h==="string"?b(k).addClass(h):b(k).css(h);typeof c==="object"&&b(k).attr(c)}}})},setCell:function(f,j,h,c,g,k){return this.each(function(){var l=-1,a,q;if(this.grid){if(isNaN(j))b(this.p.colModel).each(function(y){if(this.name==j){l=y;return false}});else l=parseInt(j,10);if(l>=0)if(a=this.rows.namedItem(f)){var x=b("td:eq("+l+")",a);if(h!==""||k===true){a=this.formatter(f,h,l,a,"edit");q=this.p.colModel[l].title?{title:b.jgrid.stripHtml(a)}:
+{};this.p.treeGrid&&b(".tree-wrap",b(x)).length>0?b("span",b(x)).html(a).attr(q):b(x).html(a).attr(q);if(this.p.datatype=="local"){a=this.p.colModel[l];h=a.formatter&&typeof a.formatter==="string"&&a.formatter=="date"?b.unformat.date(h,a):h;q=this.p._index[f];if(typeof q!="undefined")this.p.data[q][a.name]=h}}if(typeof c==="string")b(x).addClass(c);else c&&b(x).css(c);typeof g==="object"&&b(x).attr(g)}}})},getCell:function(f,j){var h=false;this.each(function(){var c=-1;if(this.grid){if(isNaN(j))b(this.p.colModel).each(function(l){if(this.name===
+j){c=l;return false}});else c=parseInt(j,10);if(c>=0){var g=this.rows.namedItem(f);if(g)try{h=b.unformat(b("td:eq("+c+")",g),{rowId:g.id,colModel:this.p.colModel[c]},c)}catch(k){h=b.jgrid.htmlDecode(b("td:eq("+c+")",g).html())}}}});return h},getCol:function(f,j,h){var c=[],g,k=0,l=0,a=0,q;j=typeof j!="boolean"?false:j;if(typeof h=="undefined")h=false;this.each(function(){var x=-1;if(this.grid){if(isNaN(f))b(this.p.colModel).each(function(M){if(this.name===f){x=M;return false}});else x=parseInt(f,
+10);if(x>=0){var y=this.rows.length,H=0;if(y&&y>0){for(;H<y;){if(b(this.rows[H]).hasClass("jqgrow")){try{g=b.unformat(b(this.rows[H].cells[x]),{rowId:this.rows[H].id,colModel:this.p.colModel[x]},x)}catch(L){g=b.jgrid.htmlDecode(this.rows[H].cells[x].innerHTML)}if(h){q=parseFloat(g);k+=q;l=Math.min(l,q);a=Math.max(l,q)}else j?c.push({id:this.rows[H].id,value:g}):c.push(g)}H++}if(h)switch(h.toLowerCase()){case "sum":c=k;break;case "avg":c=k/y;break;case "count":c=y;break;case "min":c=l;break;case "max":c=
+a}}}}});return c},clearGridData:function(f){return this.each(function(){if(this.grid){if(typeof f!="boolean")f=false;if(this.p.deepempty)b("#"+b.jgrid.jqID(this.p.id)+" tbody:first tr:gt(0)").remove();else{var j=b("#"+b.jgrid.jqID(this.p.id)+" tbody:first tr:first")[0];b("#"+b.jgrid.jqID(this.p.id)+" tbody:first").empty().append(j)}this.p.footerrow&&f&&b(".ui-jqgrid-ftable td",this.grid.sDiv).html(" ");this.p.selrow=null;this.p.selarrrow=[];this.p.savedRow=[];this.p.records=0;this.p.page=1;this.p.lastpage=
+0;this.p.reccount=0;this.p.data=[];this.p._index={};this.updatepager(true,false)}})},getInd:function(f,j){var h=false,c;this.each(function(){if(c=this.rows.namedItem(f))h=j===true?c:c.rowIndex});return h},bindKeys:function(f){var j=b.extend({onEnter:null,onSpace:null,onLeftKey:null,onRightKey:null,scrollingRows:true},f||{});return this.each(function(){var h=this;b("body").is("[role]")||b("body").attr("role","application");h.p.scrollrows=j.scrollingRows;b(h).keydown(function(c){var g=b(h).find("tr[tabindex=0]")[0],
+k,l,a,q=h.p.treeReader.expanded_field;if(g){a=h.p._index[g.id];if(c.keyCode===37||c.keyCode===38||c.keyCode===39||c.keyCode===40){if(c.keyCode===38){l=g.previousSibling;k="";if(l)if(b(l).is(":hidden"))for(;l;){l=l.previousSibling;if(!b(l).is(":hidden")&&b(l).hasClass("jqgrow")){k=l.id;break}}else k=l.id;b(h).jqGrid("setSelection",k)}if(c.keyCode===40){l=g.nextSibling;k="";if(l)if(b(l).is(":hidden"))for(;l;){l=l.nextSibling;if(!b(l).is(":hidden")&&b(l).hasClass("jqgrow")){k=l.id;break}}else k=l.id;
+b(h).jqGrid("setSelection",k)}if(c.keyCode===37){h.p.treeGrid&&h.p.data[a][q]&&b(g).find("div.treeclick").trigger("click");b.isFunction(j.onLeftKey)&&j.onLeftKey.call(h,h.p.selrow)}if(c.keyCode===39){h.p.treeGrid&&!h.p.data[a][q]&&b(g).find("div.treeclick").trigger("click");b.isFunction(j.onRightKey)&&j.onRightKey.call(h,h.p.selrow)}}else if(c.keyCode===13)b.isFunction(j.onEnter)&&j.onEnter.call(h,h.p.selrow);else c.keyCode===32&&b.isFunction(j.onSpace)&&j.onSpace.call(h,h.p.selrow)}})})},unbindKeys:function(){return this.each(function(){b(this).unbind("keydown")})},
+getLocalRow:function(f){var j=false,h;this.each(function(){if(typeof f!=="undefined"){h=this.p._index[f];if(h>=0)j=this.p.data[h]}});return j}})})(jQuery);
+(function(b){b.fmatter={};b.extend(b.fmatter,{isBoolean:function(a){return typeof a==="boolean"},isObject:function(a){return a&&(typeof a==="object"||b.isFunction(a))||false},isString:function(a){return typeof a==="string"},isNumber:function(a){return typeof a==="number"&&isFinite(a)},isNull:function(a){return a===null},isUndefined:function(a){return typeof a==="undefined"},isValue:function(a){return this.isObject(a)||this.isString(a)||this.isNumber(a)||this.isBoolean(a)},isEmpty:function(a){if(!this.isString(a)&&
+this.isValue(a))return false;else if(!this.isValue(a))return true;a=b.trim(a).replace(/\ \;/ig,"").replace(/\ \;/ig,"");return a===""}});b.fn.fmatter=function(a,c,d,e,f){var g=c;d=b.extend({},b.jgrid.formatter,d);if(b.fn.fmatter[a])g=b.fn.fmatter[a](c,d,e,f);return g};b.fmatter.util={NumberFormat:function(a,c){b.fmatter.isNumber(a)||(a*=1);if(b.fmatter.isNumber(a)){var d=a<0,e=a+"",f=c.decimalSeparator?c.decimalSeparator:".",g;if(b.fmatter.isNumber(c.decimalPlaces)){var h=c.decimalPlaces;
+e=Math.pow(10,h);e=Math.round(a*e)/e+"";g=e.lastIndexOf(".");if(h>0){if(g<0){e+=f;g=e.length-1}else if(f!==".")e=e.replace(".",f);for(;e.length-1-g<h;)e+="0"}}if(c.thousandsSeparator){h=c.thousandsSeparator;g=e.lastIndexOf(f);g=g>-1?g:e.length;f=e.substring(g);for(var i=-1,j=g;j>0;j--){i++;if(i%3===0&&j!==g&&(!d||j>1))f=h+f;f=e.charAt(j-1)+f}e=f}e=c.prefix?c.prefix+e:e;return e=c.suffix?e+c.suffix:e}else return a},DateFormat:function(a,c,d,e){var f=/^\/Date\((([-+])?[0-9]+)(([-+])([0-9]{2})([0-9]{2}))?\)\/$/,
+g=typeof c==="string"?c.match(f):null;f=function(m,r){m=String(m);for(r=parseInt(r,10)||2;m.length<r;)m="0"+m;return m};var h={m:1,d:1,y:1970,h:0,i:0,s:0,u:0},i=0,j,k=["i18n"];k.i18n={dayNames:e.dayNames,monthNames:e.monthNames};if(a in e.masks)a=e.masks[a];if(c.constructor===Number){if(String(a).toLowerCase()=="u")c*=1E3;i=new Date(c)}else if(c.constructor===Date)i=c;else if(g!==null){i=new Date(parseInt(g[1],10));if(g[3]){a=Number(g[5])*60+Number(g[6]);a*=g[4]=="-"?1:-1;a-=i.getTimezoneOffset();
+i.setTime(Number(Number(i)+a*6E4))}}else{c=String(c).split(/[\\\/:_;.,\t\T\s-]/);a=a.split(/[\\\/:_;.,\t\T\s-]/);g=0;for(j=a.length;g<j;g++){if(a[g]=="M"){i=b.inArray(c[g],k.i18n.monthNames);if(i!==-1&&i<12)c[g]=i+1}if(a[g]=="F"){i=b.inArray(c[g],k.i18n.monthNames);if(i!==-1&&i>11)c[g]=i+1-12}if(c[g])h[a[g].toLowerCase()]=parseInt(c[g],10)}if(h.f)h.m=h.f;if(h.m===0&&h.y===0&&h.d===0)return" ";h.m=parseInt(h.m,10)-1;i=h.y;if(i>=70&&i<=99)h.y=1900+h.y;else if(i>=0&&i<=69)h.y=2E3+h.y;i=new Date(h.y,
+h.m,h.d,h.h,h.i,h.s,h.u)}if(d in e.masks)d=e.masks[d];else d||(d="Y-m-d");a=i.getHours();c=i.getMinutes();h=i.getDate();g=i.getMonth()+1;j=i.getTimezoneOffset();var l=i.getSeconds(),o=i.getMilliseconds(),n=i.getDay(),p=i.getFullYear(),q=(n+6)%7+1,s=(new Date(p,g-1,h)-new Date(p,0,1))/864E5,t={d:f(h),D:k.i18n.dayNames[n],j:h,l:k.i18n.dayNames[n+7],N:q,S:e.S(h),w:n,z:s,W:q<5?Math.floor((s+q-1)/7)+1:Math.floor((s+q-1)/7)||(((new Date(p-1,0,1)).getDay()+6)%7<4?53:52),F:k.i18n.monthNames[g-1+12],m:f(g),
+M:k.i18n.monthNames[g-1],n:g,t:"?",L:"?",o:"?",Y:p,y:String(p).substring(2),a:a<12?e.AmPm[0]:e.AmPm[1],A:a<12?e.AmPm[2]:e.AmPm[3],B:"?",g:a%12||12,G:a,h:f(a%12||12),H:f(a),i:f(c),s:f(l),u:o,e:"?",I:"?",O:(j>0?"-":"+")+f(Math.floor(Math.abs(j)/60)*100+Math.abs(j)%60,4),P:"?",T:(String(i).match(/\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g)||[""]).pop().replace(/[^-+\dA-Z]/g,""),Z:"?",c:"?",r:"?",U:Math.floor(i/
+1E3)};return d.replace(/\\.|[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]/g,function(m){return m in t?t[m]:m.substring(1)})}};b.fn.fmatter.defaultFormat=function(a,c){return b.fmatter.isValue(a)&&a!==""?a:c.defaultValue?c.defaultValue:" "};b.fn.fmatter.email=function(a,c){return b.fmatter.isEmpty(a)?b.fn.fmatter.defaultFormat(a,c):'<a href="mailto:'+a+'">'+a+"</a>"};b.fn.fmatter.checkbox=function(a,c){var d=b.extend({},c.checkbox),e;b.fmatter.isUndefined(c.colModel.formatoptions)||(d=b.extend({},d,
+c.colModel.formatoptions));e=d.disabled===true?'disabled="disabled"':"";if(b.fmatter.isEmpty(a)||b.fmatter.isUndefined(a))a=b.fn.fmatter.defaultFormat(a,d);a+="";a=a.toLowerCase();return'<input type="checkbox" '+(a.search(/(false|0|no|off)/i)<0?" checked='checked' ":"")+' value="'+a+'" offval="no" '+e+"/>"};b.fn.fmatter.link=function(a,c){var d={target:c.target},e="";b.fmatter.isUndefined(c.colModel.formatoptions)||(d=b.extend({},d,c.colModel.formatoptions));if(d.target)e="target="+d.target;return b.fmatter.isEmpty(a)?
+b.fn.fmatter.defaultFormat(a,c):"<a "+e+' href="'+a+'">'+a+"</a>"};b.fn.fmatter.showlink=function(a,c){var d={baseLinkUrl:c.baseLinkUrl,showAction:c.showAction,addParam:c.addParam||"",target:c.target,idName:c.idName},e="";b.fmatter.isUndefined(c.colModel.formatoptions)||(d=b.extend({},d,c.colModel.formatoptions));if(d.target)e="target="+d.target;d=d.baseLinkUrl+d.showAction+"?"+d.idName+"="+c.rowId+d.addParam;return b.fmatter.isString(a)||b.fmatter.isNumber(a)?"<a "+e+' href="'+d+'">'+a+"</a>":b.fn.fmatter.defaultFormat(a,
+c)};b.fn.fmatter.integer=function(a,c){var d=b.extend({},c.integer);b.fmatter.isUndefined(c.colModel.formatoptions)||(d=b.extend({},d,c.colModel.formatoptions));if(b.fmatter.isEmpty(a))return d.defaultValue;return b.fmatter.util.NumberFormat(a,d)};b.fn.fmatter.number=function(a,c){var d=b.extend({},c.number);b.fmatter.isUndefined(c.colModel.formatoptions)||(d=b.extend({},d,c.colModel.formatoptions));if(b.fmatter.isEmpty(a))return d.defaultValue;return b.fmatter.util.NumberFormat(a,d)};b.fn.fmatter.currency=
+function(a,c){var d=b.extend({},c.currency);b.fmatter.isUndefined(c.colModel.formatoptions)||(d=b.extend({},d,c.colModel.formatoptions));if(b.fmatter.isEmpty(a))return d.defaultValue;return b.fmatter.util.NumberFormat(a,d)};b.fn.fmatter.date=function(a,c,d,e){d=b.extend({},c.date);b.fmatter.isUndefined(c.colModel.formatoptions)||(d=b.extend({},d,c.colModel.formatoptions));return!d.reformatAfterEdit&&e=="edit"?b.fn.fmatter.defaultFormat(a,c):b.fmatter.isEmpty(a)?b.fn.fmatter.defaultFormat(a,c):b.fmatter.util.DateFormat(d.srcformat,
+a,d.newformat,d)};b.fn.fmatter.select=function(a,c){a+="";var d=false,e=[];if(b.fmatter.isUndefined(c.colModel.formatoptions)){if(!b.fmatter.isUndefined(c.colModel.editoptions))d=c.colModel.editoptions.value}else d=c.colModel.formatoptions.value;if(d){var f=c.colModel.editoptions.multiple===true?true:false,g=[],h;if(f){g=a.split(",");g=b.map(g,function(l){return b.trim(l)})}if(b.fmatter.isString(d))for(var i=d.split(";"),j=0,k=0;k<i.length;k++){h=i[k].split(":");if(h.length>2)h[1]=jQuery.map(h,function(l,
+o){if(o>0)return l}).join(":");if(f){if(jQuery.inArray(h[0],g)>-1){e[j]=h[1];j++}}else if(b.trim(h[0])==b.trim(a)){e[0]=h[1];break}}else if(b.fmatter.isObject(d))if(f)e=jQuery.map(g,function(l){return d[l]});else e[0]=d[a]||""}a=e.join(", ");return a===""?b.fn.fmatter.defaultFormat(a,c):a};b.fn.fmatter.rowactions=function(a,c,d,e){var f={keys:false,onEdit:null,onSuccess:null,afterSave:null,onError:null,afterRestore:null,extraparam:{oper:"edit"},url:null,delOptions:{},editOptions:{}};a=b.jgrid.jqID(a);
+c=b.jgrid.jqID(c);e=b("#"+c)[0].p.colModel[e];b.fmatter.isUndefined(e.formatoptions)||(f=b.extend(f,e.formatoptions));if(!b.fmatter.isUndefined(b("#"+c)[0].p.editOptions))f.editOptions=b("#"+c)[0].p.editOptions;if(!b.fmatter.isUndefined(b("#"+c)[0].p.delOptions))f.delOptions=b("#"+c)[0].p.delOptions;e=function(h){f.afterSave&&f.afterSave(h);b("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+c+".ui-jqgrid-btable:first").show();b("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel",
+"#"+c+".ui-jqgrid-btable:first").hide()};var g=function(h){f.afterRestore&&f.afterRestore(h);b("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+c+".ui-jqgrid-btable:first").show();b("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+c+".ui-jqgrid-btable:first").hide()};switch(d){case "edit":b("#"+c).jqGrid("editRow",a,f.keys,f.onEdit,f.onSuccess,f.url,f.extraparam,e,f.onError,g);b("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+c+".ui-jqgrid-btable:first").hide();
+b("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+c+".ui-jqgrid-btable:first").show();break;case "save":if(b("#"+c).jqGrid("saveRow",a,f.onSuccess,f.url,f.extraparam,e,f.onError,g)){b("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del","#"+c+".ui-jqgrid-btable:first").show();b("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+c+".ui-jqgrid-btable:first").hide()}break;case "cancel":b("#"+c).jqGrid("restoreRow",a,g);b("tr#"+a+" div.ui-inline-edit, tr#"+a+" div.ui-inline-del",
+"#"+c+".ui-jqgrid-btable:first").show();b("tr#"+a+" div.ui-inline-save, tr#"+a+" div.ui-inline-cancel","#"+c+".ui-jqgrid-btable:first").hide();break;case "del":b("#"+c).jqGrid("delGridRow",a,f.delOptions);break;case "formedit":b("#"+c).jqGrid("setSelection",a);b("#"+c).jqGrid("editGridRow",a,f.editOptions)}};b.fn.fmatter.actions=function(a,c){var d={keys:false,editbutton:true,delbutton:true,editformbutton:false};b.fmatter.isUndefined(c.colModel.formatoptions)||(d=b.extend(d,c.colModel.formatoptions));
+var e=c.rowId,f="",g;if(typeof e=="undefined"||b.fmatter.isEmpty(e))return"";if(d.editformbutton){g="onclick=$.fn.fmatter.rowactions('"+e+"','"+c.gid+"','formedit',"+c.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ";f=f+"<div title='"+b.jgrid.nav.edittitle+"' style='float:left;cursor:pointer;' class='ui-pg-div ui-inline-edit' "+g+"><span class='ui-icon ui-icon-pencil'></span></div>"}else if(d.editbutton){g="onclick=$.fn.fmatter.rowactions('"+
+e+"','"+c.gid+"','edit',"+c.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover') ";f=f+"<div title='"+b.jgrid.nav.edittitle+"' style='float:left;cursor:pointer;' class='ui-pg-div ui-inline-edit' "+g+"><span class='ui-icon ui-icon-pencil'></span></div>"}if(d.delbutton){g="onclick=$.fn.fmatter.rowactions('"+e+"','"+c.gid+"','del',"+c.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ";
+f=f+"<div title='"+b.jgrid.nav.deltitle+"' style='float:left;margin-left:5px;' class='ui-pg-div ui-inline-del' "+g+"><span class='ui-icon ui-icon-trash'></span></div>"}g="onclick=$.fn.fmatter.rowactions('"+e+"','"+c.gid+"','save',"+c.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ";f=f+"<div title='"+b.jgrid.edit.bSubmit+"' style='float:left;display:none' class='ui-pg-div ui-inline-save' "+g+"><span class='ui-icon ui-icon-disk'></span></div>";
+g="onclick=$.fn.fmatter.rowactions('"+e+"','"+c.gid+"','cancel',"+c.pos+"); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ";f=f+"<div title='"+b.jgrid.edit.bCancel+"' style='float:left;display:none;margin-left:5px;' class='ui-pg-div ui-inline-cancel' "+g+"><span class='ui-icon ui-icon-cancel'></span></div>";return"<div style='margin-left:8px;'>"+f+"</div>"};b.unformat=function(a,c,d,e){var f,g=c.colModel.formatter,h=c.colModel.formatoptions||
+{},i=/([\.\*\_\'\(\)\{\}\+\?\\])/g,j=c.colModel.unformat||b.fn.fmatter[g]&&b.fn.fmatter[g].unformat;if(typeof j!=="undefined"&&b.isFunction(j))f=j(b(a).text(),c,a);else if(!b.fmatter.isUndefined(g)&&b.fmatter.isString(g)){f=b.jgrid.formatter||{};switch(g){case "integer":h=b.extend({},f.integer,h);c=h.thousandsSeparator.replace(i,"\\$1");f=b(a).text().replace(RegExp(c,"g"),"");break;case "number":h=b.extend({},f.number,h);c=h.thousandsSeparator.replace(i,"\\$1");f=b(a).text().replace(RegExp(c,"g"),
+"").replace(h.decimalSeparator,".");break;case "currency":h=b.extend({},f.currency,h);c=h.thousandsSeparator.replace(i,"\\$1");f=b(a).text().replace(RegExp(c,"g"),"").replace(h.decimalSeparator,".").replace(h.prefix,"").replace(h.suffix,"");break;case "checkbox":h=c.colModel.editoptions?c.colModel.editoptions.value.split(":"):["Yes","No"];f=b("input",a).attr("checked")?h[0]:h[1];break;case "select":f=b.unformat.select(a,c,d,e);break;case "actions":return"";default:f=b(a).text()}}return f!==undefined?
+f:e===true?b(a).text():b.jgrid.htmlDecode(b(a).html())};b.unformat.select=function(a,c,d,e){d=[];a=b(a).text();if(e===true)return a;c=b.extend({},c.colModel.editoptions);if(c.value){var f=c.value;c=c.multiple===true?true:false;e=[];var g;if(c){e=a.split(",");e=b.map(e,function(k){return b.trim(k)})}if(b.fmatter.isString(f))for(var h=f.split(";"),i=0,j=0;j<h.length;j++){g=h[j].split(":");if(g.length>2)g[1]=jQuery.map(g,function(k,l){if(l>0)return k}).join(":");if(c){if(jQuery.inArray(g[1],e)>-1){d[i]=
+g[0];i++}}else if(b.trim(g[1])==b.trim(a)){d[0]=g[0];break}}else if(b.fmatter.isObject(f)||b.isArray(f)){c||(e[0]=a);d=jQuery.map(e,function(k){var l;b.each(f,function(o,n){if(n==k){l=o;return false}});if(typeof l!="undefined")return l})}return d.join(", ")}else return a||""};b.unformat.date=function(a,c){var d=b.jgrid.formatter.date||{};b.fmatter.isUndefined(c.formatoptions)||(d=b.extend({},d,c.formatoptions));return b.fmatter.isEmpty(a)?b.fn.fmatter.defaultFormat(a,c):b.fmatter.util.DateFormat(d.newformat,
+a,d.srcformat,d)}})(jQuery);
+(function(a){a.jgrid.extend({getColProp:function(c){var h={},b=this[0];if(!b.grid)return false;b=b.p.colModel;for(var i=0;i<b.length;i++)if(b[i].name==c){h=b[i];break}return h},setColProp:function(c,h){return this.each(function(){if(this.grid)if(h)for(var b=this.p.colModel,i=0;i<b.length;i++)if(b[i].name==c){a.extend(this.p.colModel[i],h);break}})},sortGrid:function(c,h,b){return this.each(function(){var i=-1;if(this.grid){if(!c)c=this.p.sortname;for(var o=0;o<this.p.colModel.length;o++)if(this.p.colModel[o].index==
+c||this.p.colModel[o].name==c){i=o;break}if(i!=-1){o=this.p.colModel[i].sortable;if(typeof o!=="boolean")o=true;if(typeof h!=="boolean")h=false;o&&this.sortData("jqgh_"+this.p.id+"_"+c,i,h,b)}}})},GridDestroy:function(){return this.each(function(){if(this.grid){this.p.pager&&a(this.p.pager).remove();var c=this.id;try{a("#gbox_"+c).remove()}catch(h){}}})},GridUnload:function(){return this.each(function(){if(this.grid){var c={id:a(this).attr("id"),cl:a(this).attr("class")};this.p.pager&&a(this.p.pager).empty().removeClass("ui-state-default ui-jqgrid-pager corner-bottom");
+var h=document.createElement("table");a(h).attr({id:c.id});h.className=c.cl;c=this.id;a(h).removeClass("ui-jqgrid-btable");if(a(this.p.pager).parents("#gbox_"+c).length===1){a(h).insertBefore("#gbox_"+c).show();a(this.p.pager).insertBefore("#gbox_"+c)}else a(h).insertBefore("#gbox_"+c).show();a("#gbox_"+c).remove()}})},setGridState:function(c){return this.each(function(){if(this.grid)if(c=="hidden"){a(".ui-jqgrid-bdiv, .ui-jqgrid-hdiv","#gview_"+this.p.id).slideUp("fast");this.p.pager&&a(this.p.pager).slideUp("fast");
+this.p.toppager&&a(this.p.toppager).slideUp("fast");if(this.p.toolbar[0]===true){this.p.toolbar[1]=="both"&&a(this.grid.ubDiv).slideUp("fast");a(this.grid.uDiv).slideUp("fast")}this.p.footerrow&&a(".ui-jqgrid-sdiv","#gbox_"+this.p.id).slideUp("fast");a(".ui-jqgrid-titlebar-close span",this.grid.cDiv).removeClass("ui-icon-circle-triangle-n").addClass("ui-icon-circle-triangle-s");this.p.gridstate="hidden"}else if(c=="visible"){a(".ui-jqgrid-hdiv, .ui-jqgrid-bdiv","#gview_"+this.p.id).slideDown("fast");
+this.p.pager&&a(this.p.pager).slideDown("fast");this.p.toppager&&a(this.p.toppager).slideDown("fast");if(this.p.toolbar[0]===true){this.p.toolbar[1]=="both"&&a(this.grid.ubDiv).slideDown("fast");a(this.grid.uDiv).slideDown("fast")}this.p.footerrow&&a(".ui-jqgrid-sdiv","#gbox_"+this.p.id).slideDown("fast");a(".ui-jqgrid-titlebar-close span",this.grid.cDiv).removeClass("ui-icon-circle-triangle-s").addClass("ui-icon-circle-triangle-n");this.p.gridstate="visible"}})},filterToolbar:function(c){c=a.extend({autosearch:true,
+searchOnEnter:true,beforeSearch:null,afterSearch:null,beforeClear:null,afterClear:null,searchurl:"",stringResult:false,groupOp:"AND",defaultSearch:"bw"},c||{});return this.each(function(){function h(e,f){var j=a(e);j[0]&&jQuery.each(f,function(){this.data!==undefined?j.bind(this.type,this.data,this.fn):j.bind(this.type,this.fn)})}var b=this;if(!this.ftoolbar){var i=function(){var e={},f=0,j,d,g={},k;a.each(b.p.colModel,function(){d=this.index||this.name;switch(this.stype){case "select":k=this.searchoptions&&
+this.searchoptions.sopt?this.searchoptions.sopt[0]:"eq";if(j=a("#gs_"+a.jgrid.jqID(this.name),b.grid.hDiv).val()){e[d]=j;g[d]=k;f++}else try{delete b.p.postData[d]}catch(p){}break;case "text":k=this.searchoptions&&this.searchoptions.sopt?this.searchoptions.sopt[0]:c.defaultSearch;if(j=a("#gs_"+a.jgrid.jqID(this.name),b.grid.hDiv).val()){e[d]=j;g[d]=k;f++}else try{delete b.p.postData[d]}catch(s){}}});var n=f>0?true:false;if(c.stringResult===true||b.p.datatype=="local"){var m='{"groupOp":"'+c.groupOp+
+'","rules":[',q=0;a.each(e,function(p,s){if(q>0)m+=",";m+='{"field":"'+p+'",';m+='"op":"'+g[p]+'",';s+="";m+='"data":"'+s.replace(/\\/g,"\\\\").replace(/\"/g,'\\"')+'"}';q++});m+="]}";a.extend(b.p.postData,{filters:m});a.each(["searchField","searchString","searchOper"],function(p,s){b.p.postData.hasOwnProperty(s)&&delete b.p.postData[s]})}else a.extend(b.p.postData,e);var l;if(b.p.searchurl){l=b.p.url;a(b).jqGrid("setGridParam",{url:b.p.searchurl})}var r=false;if(a.isFunction(c.beforeSearch))r=c.beforeSearch.call(b);
+r||a(b).jqGrid("setGridParam",{search:n}).trigger("reloadGrid",[{page:1}]);l&&a(b).jqGrid("setGridParam",{url:l});a.isFunction(c.afterSearch)&&c.afterSearch()},o=a("<tr class='ui-search-toolbar' role='rowheader'></tr>"),t;a.each(b.p.colModel,function(){var e=this,f,j,d,g;j=a("<th role='columnheader' class='ui-state-default ui-th-column ui-th-"+b.p.direction+"'></th>");f=a("<div style='width:100%;position:relative;height:100%;padding-right:0.3em;'></div>");this.hidden===true&&a(j).css("display","none");
+this.search=this.search===false?false:true;if(typeof this.stype=="undefined")this.stype="text";d=a.extend({},this.searchoptions||{});if(this.search)switch(this.stype){case "select":if(g=this.surl||d.dataUrl)a.ajax(a.extend({url:g,dataType:"html",complete:function(l){if(d.buildSelect!==undefined)(l=d.buildSelect(l))&&a(f).append(l);else a(f).append(l.responseText);d.defaultValue&&a("select",f).val(d.defaultValue);a("select",f).attr({name:e.index||e.name,id:"gs_"+e.name});d.attr&&a("select",f).attr(d.attr);
+a("select",f).css({width:"100%"});d.dataInit!==undefined&&d.dataInit(a("select",f)[0]);d.dataEvents!==undefined&&h(a("select",f)[0],d.dataEvents);c.autosearch===true&&a("select",f).change(function(){i();return false});l=null}},a.jgrid.ajaxOptions,b.p.ajaxSelectOptions||{}));else{var k;if(e.searchoptions&&e.searchoptions.value)k=e.searchoptions.value;else if(e.editoptions&&e.editoptions.value)k=e.editoptions.value;if(k){g=document.createElement("select");g.style.width="100%";a(g).attr({name:e.index||
+e.name,id:"gs_"+e.name});var n,m;if(typeof k==="string"){k=k.split(";");for(var q=0;q<k.length;q++){n=k[q].split(":");m=document.createElement("option");m.value=n[0];m.innerHTML=n[1];g.appendChild(m)}}else if(typeof k==="object")for(n in k)if(k.hasOwnProperty(n)){m=document.createElement("option");m.value=n;m.innerHTML=k[n];g.appendChild(m)}d.defaultValue&&a(g).val(d.defaultValue);d.attr&&a(g).attr(d.attr);d.dataInit!==undefined&&d.dataInit(g);d.dataEvents!==undefined&&h(g,d.dataEvents);a(f).append(g);
+c.autosearch===true&&a(g).change(function(){i();return false})}}break;case "text":g=d.defaultValue?d.defaultValue:"";a(f).append("<input type='text' style='width:95%;padding:0px;' name='"+(e.index||e.name)+"' id='gs_"+e.name+"' value='"+g+"'/>");d.attr&&a("input",f).attr(d.attr);d.dataInit!==undefined&&d.dataInit(a("input",f)[0]);d.dataEvents!==undefined&&h(a("input",f)[0],d.dataEvents);if(c.autosearch===true)c.searchOnEnter?a("input",f).keypress(function(l){if((l.charCode?l.charCode:l.keyCode?l.keyCode:
+0)==13){i();return false}return this}):a("input",f).keydown(function(l){switch(l.which){case 13:return false;case 9:case 16:case 37:case 38:case 39:case 40:case 27:break;default:t&&clearTimeout(t);t=setTimeout(function(){i()},500)}})}a(j).append(f);a(o).append(j)});a("table thead",b.grid.hDiv).append(o);this.ftoolbar=true;this.triggerToolbar=i;this.clearToolbar=function(e){var f={},j,d=0,g;e=typeof e!="boolean"?true:e;a.each(b.p.colModel,function(){j=this.searchoptions&&this.searchoptions.defaultValue?
+this.searchoptions.defaultValue:"";g=this.index||this.name;switch(this.stype){case "select":var r;a("#gs_"+a.jgrid.jqID(g)+" option",b.grid.hDiv).each(function(u){if(u===0)this.selected=true;if(a(this).text()==j){this.selected=true;r=a(this).val();return false}});if(r){f[g]=r;d++}else try{delete b.p.postData[g]}catch(p){}break;case "text":a("#gs_"+a.jgrid.jqID(g),b.grid.hDiv).val(j);if(j){f[g]=j;d++}else try{delete b.p.postData[g]}catch(s){}}});var k=d>0?true:false;if(c.stringResult===true||b.p.datatype==
+"local"){var n='{"groupOp":"'+c.groupOp+'","rules":[',m=0;a.each(f,function(r,p){if(m>0)n+=",";n+='{"field":"'+r+'",';n+='"op":"eq",';p+="";n+='"data":"'+p.replace(/\\/g,"\\\\").replace(/\"/g,'\\"')+'"}';m++});n+="]}";a.extend(b.p.postData,{filters:n});a.each(["searchField","searchString","searchOper"],function(r,p){b.p.postData.hasOwnProperty(p)&&delete b.p.postData[p]})}else a.extend(b.p.postData,f);var q;if(b.p.searchurl){q=b.p.url;a(b).jqGrid("setGridParam",{url:b.p.searchurl})}var l=false;if(a.isFunction(c.beforeClear))l=
+c.beforeClear.call(b);l||e&&a(b).jqGrid("setGridParam",{search:k}).trigger("reloadGrid",[{page:1}]);q&&a(b).jqGrid("setGridParam",{url:q});a.isFunction(c.afterClear)&&c.afterClear()};this.toggleToolbar=function(){var e=a("tr.ui-search-toolbar",b.grid.hDiv);e.css("display")=="none"?e.show():e.hide()}}})}})})(jQuery);
+(function(a){a.extend(a.jgrid,{showModal:function(b){b.w.show()},closeModal:function(b){b.w.hide().attr("aria-hidden","true");b.o&&b.o.remove()},hideModal:function(b,c){c=a.extend({jqm:true,gb:""},c||{});if(c.onClose){var d=c.onClose(b);if(typeof d=="boolean"&&!d)return}if(a.fn.jqm&&c.jqm===true)a(b).attr("aria-hidden","true").jqmHide();else{if(c.gb!=="")try{a(".jqgrid-overlay:first",c.gb).hide()}catch(f){}a(b).hide().attr("aria-hidden","true")}},findPos:function(b){var c=0,d=0;if(b.offsetParent){do{c+=
+b.offsetLeft;d+=b.offsetTop}while(b=b.offsetParent)}return[c,d]},createModal:function(b,c,d,f,g,h,j){var e=document.createElement("div"),k,m=this;j=a.extend({},j||{});k=a(d.gbox).attr("dir")=="rtl"?true:false;e.className="ui-widget ui-widget-content ui-corner-all ui-jqdialog";e.id=b.themodal;var i=document.createElement("div");i.className="ui-jqdialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix";i.id=b.modalhead;a(i).append("<span class='ui-jqdialog-title'>"+d.caption+"</span>");var q=
+a("<a href='javascript:void(0)' class='ui-jqdialog-titlebar-close ui-corner-all'></a>").hover(function(){q.addClass("ui-state-hover")},function(){q.removeClass("ui-state-hover")}).append("<span class='ui-icon ui-icon-closethick'></span>");a(i).append(q);if(k){e.dir="rtl";a(".ui-jqdialog-title",i).css("float","right");a(".ui-jqdialog-titlebar-close",i).css("left","0.3em")}else{e.dir="ltr";a(".ui-jqdialog-title",i).css("float","left");a(".ui-jqdialog-titlebar-close",i).css("right","0.3em")}var l=document.createElement("div");
+a(l).addClass("ui-jqdialog-content ui-widget-content").attr("id",b.modalcontent);a(l).append(c);e.appendChild(l);a(e).prepend(i);if(h===true)a("body").append(e);else typeof h=="string"?a(h).append(e):a(e).insertBefore(f);a(e).css(j);if(typeof d.jqModal==="undefined")d.jqModal=true;c={};if(a.fn.jqm&&d.jqModal===true){if(d.left===0&&d.top===0&&d.overlay){j=[];j=this.findPos(g);d.left=j[0]+4;d.top=j[1]+4}c.top=d.top+"px";c.left=d.left}else if(d.left!==0||d.top!==0){c.left=d.left;c.top=d.top+"px"}a("a.ui-jqdialog-titlebar-close",
+i).click(function(){var p=a("#"+b.themodal).data("onClose")||d.onClose,o=a("#"+b.themodal).data("gbox")||d.gbox;m.hideModal("#"+b.themodal,{gb:o,jqm:d.jqModal,onClose:p});return false});if(d.width===0||!d.width)d.width=300;if(d.height===0||!d.height)d.height=200;if(!d.zIndex){f=a(f).parents("*[role=dialog]").filter(":first").css("z-index");d.zIndex=f?parseInt(f,10)+1:950}f=0;if(k&&c.left&&!h){f=a(d.gbox).width()-(!isNaN(d.width)?parseInt(d.width,10):0)-8;c.left=parseInt(c.left,10)+parseInt(f,10)}if(c.left)c.left+=
+"px";a(e).css(a.extend({width:isNaN(d.width)?"auto":d.width+"px",height:isNaN(d.height)?"auto":d.height+"px",zIndex:d.zIndex,overflow:"hidden"},c)).attr({tabIndex:"-1",role:"dialog","aria-labelledby":b.modalhead,"aria-hidden":"true"});if(typeof d.drag=="undefined")d.drag=true;if(typeof d.resize=="undefined")d.resize=true;if(d.drag){a(i).css("cursor","move");if(a.fn.jqDrag)a(e).jqDrag(i);else try{a(e).draggable({handle:a("#"+i.id)})}catch(n){}}if(d.resize)if(a.fn.jqResize){a(e).append("<div class='jqResize ui-resizable-handle ui-resizable-se ui-icon ui-icon-gripsmall-diagonal-se ui-icon-grip-diagonal-se'></div>");
+a("#"+b.themodal).jqResize(".jqResize",b.scrollelm?"#"+b.scrollelm:false)}else try{a(e).resizable({handles:"se, sw",alsoResize:b.scrollelm?"#"+b.scrollelm:false})}catch(r){}d.closeOnEscape===true&&a(e).keydown(function(p){if(p.which==27){p=a("#"+b.themodal).data("onClose")||d.onClose;m.hideModal(this,{gb:d.gbox,jqm:d.jqModal,onClose:p})}})},viewModal:function(b,c){c=a.extend({toTop:true,overlay:10,modal:false,overlayClass:"ui-widget-overlay",onShow:this.showModal,onHide:this.closeModal,gbox:"",jqm:true,
+jqM:true},c||{});if(a.fn.jqm&&c.jqm===true)c.jqM?a(b).attr("aria-hidden","false").jqm(c).jqmShow():a(b).attr("aria-hidden","false").jqmShow();else{if(c.gbox!==""){a(".jqgrid-overlay:first",c.gbox).show();a(b).data("gbox",c.gbox)}a(b).show().attr("aria-hidden","false");try{a(":input:visible",b)[0].focus()}catch(d){}}},info_dialog:function(b,c,d,f){var g={width:290,height:"auto",dataheight:"auto",drag:true,resize:false,caption:"<b>"+b+"</b>",left:250,top:170,zIndex:1E3,jqModal:true,modal:false,closeOnEscape:true,
+align:"center",buttonalign:"center",buttons:[]};a.extend(g,f||{});var h=g.jqModal,j=this;if(a.fn.jqm&&!h)h=false;b="";if(g.buttons.length>0)for(f=0;f<g.buttons.length;f++){if(typeof g.buttons[f].id=="undefined")g.buttons[f].id="info_button_"+f;b+="<a href='javascript:void(0)' id='"+g.buttons[f].id+"' class='fm-button ui-state-default ui-corner-all'>"+g.buttons[f].text+"</a>"}f=isNaN(g.dataheight)?g.dataheight:g.dataheight+"px";var e="<div id='info_id'>";e+="<div id='infocnt' style='margin:0px;padding-bottom:1em;width:100%;overflow:auto;position:relative;height:"+
+f+";"+("text-align:"+g.align+";")+"'>"+c+"</div>";e+=d?"<div class='ui-widget-content ui-helper-clearfix' style='text-align:"+g.buttonalign+";padding-bottom:0.8em;padding-top:0.5em;background-image: none;border-width: 1px 0 0 0;'><a href='javascript:void(0)' id='closedialog' class='fm-button ui-state-default ui-corner-all'>"+d+"</a>"+b+"</div>":b!==""?"<div class='ui-widget-content ui-helper-clearfix' style='text-align:"+g.buttonalign+";padding-bottom:0.8em;padding-top:0.5em;background-image: none;border-width: 1px 0 0 0;'>"+
+b+"</div>":"";e+="</div>";try{a("#info_dialog").attr("aria-hidden")=="false"&&this.hideModal("#info_dialog",{jqm:h});a("#info_dialog").remove()}catch(k){}this.createModal({themodal:"info_dialog",modalhead:"info_head",modalcontent:"info_content",scrollelm:"infocnt"},e,g,"","",true);b&&a.each(g.buttons,function(i){a("#"+this.id,"#info_id").bind("click",function(){g.buttons[i].onClick.call(a("#info_dialog"));return false})});a("#closedialog","#info_id").click(function(){j.hideModal("#info_dialog",{jqm:h});
+return false});a(".fm-button","#info_dialog").hover(function(){a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")});a.isFunction(g.beforeOpen)&&g.beforeOpen();this.viewModal("#info_dialog",{onHide:function(i){i.w.hide().remove();i.o&&i.o.remove()},modal:g.modal,jqm:h});a.isFunction(g.afterOpen)&&g.afterOpen();try{a("#info_dialog").focus()}catch(m){}},createEl:function(b,c,d,f,g){function h(l,n){a.isFunction(n.dataInit)&&n.dataInit(l);n.dataEvents&&a.each(n.dataEvents,
+function(){this.data!==undefined?a(l).bind(this.type,this.data,this.fn):a(l).bind(this.type,this.fn)});return n}function j(l,n,r){var p=["dataInit","dataEvents","dataUrl","buildSelect","sopt","searchhidden","defaultValue","attr"];if(typeof r!="undefined"&&a.isArray(r))p=a.extend(p,r);a.each(n,function(o,s){a.inArray(o,p)===-1&&a(l).attr(o,s)});n.hasOwnProperty("id")||a(l).attr("id",a.jgrid.randId())}var e="";switch(b){case "textarea":e=document.createElement("textarea");if(f)c.cols||a(e).css({width:"98%"});
+else if(!c.cols)c.cols=20;if(!c.rows)c.rows=2;if(d==" "||d==" "||d.length==1&&d.charCodeAt(0)==160)d="";e.value=d;j(e,c);c=h(e,c);a(e).attr({role:"textbox",multiline:"true"});break;case "checkbox":e=document.createElement("input");e.type="checkbox";if(c.value){b=c.value.split(":");if(d===b[0]){e.checked=true;e.defaultChecked=true}e.value=b[0];a(e).attr("offval",b[1])}else{b=d.toLowerCase();if(b.search(/(false|0|no|off|undefined)/i)<0&&b!==""){e.checked=true;e.defaultChecked=true;e.value=
+d}else e.value="on";a(e).attr("offval","off")}j(e,c,["value"]);c=h(e,c);a(e).attr("role","checkbox");break;case "select":e=document.createElement("select");e.setAttribute("role","select");f=[];if(c.multiple===true){b=true;e.multiple="multiple";a(e).attr("aria-multiselectable","true")}else b=false;if(typeof c.dataUrl!="undefined")a.ajax(a.extend({url:c.dataUrl,type:"GET",dataType:"html",context:{elem:e,options:c,vl:d},success:function(l){var n=[],r=this.elem,p=this.vl,o=a.extend({},this.options),s=
+o.multiple===true;if(typeof o.buildSelect!="undefined")l=o.buildSelect(l);if(l=a(l).html()){a(r).append(l);j(r,o);o=h(r,o);if(typeof o.size==="undefined")o.size=s?3:1;if(s){n=p.split(",");n=a.map(n,function(t){return a.trim(t)})}else n[0]=a.trim(p);setTimeout(function(){a("option",r).each(function(){a(this).attr("role","option");if(a.inArray(a.trim(a(this).text()),n)>-1||a.inArray(a.trim(a(this).val()),n)>-1)this.selected="selected"})},0)}}},g||{}));else if(c.value){var k;if(b){f=d.split(",");f=a.map(f,
+function(l){return a.trim(l)});if(typeof c.size==="undefined")c.size=3}else c.size=1;if(typeof c.value==="function")c.value=c.value();var m,i;if(typeof c.value==="string"){m=c.value.split(";");for(k=0;k<m.length;k++){i=m[k].split(":");if(i.length>2)i[1]=a.map(i,function(l,n){if(n>0)return l}).join(":");g=document.createElement("option");g.setAttribute("role","option");g.value=i[0];g.innerHTML=i[1];if(!b&&(a.trim(i[0])==a.trim(d)||a.trim(i[1])==a.trim(d)))g.selected="selected";if(b&&(a.inArray(a.trim(i[1]),
+f)>-1||a.inArray(a.trim(i[0]),f)>-1))g.selected="selected";e.appendChild(g)}}else if(typeof c.value==="object"){m=c.value;for(k in m)if(m.hasOwnProperty(k)){g=document.createElement("option");g.setAttribute("role","option");g.value=k;g.innerHTML=m[k];if(!b&&(a.trim(k)==a.trim(d)||a.trim(m[k])==a.trim(d)))g.selected="selected";if(b&&(a.inArray(a.trim(m[k]),f)>-1||a.inArray(a.trim(k),f)>-1))g.selected="selected";e.appendChild(g)}}j(e,c,["value"]);c=h(e,c)}break;case "text":case "password":case "button":k=
+b=="button"?"button":"textbox";e=document.createElement("input");e.type=b;e.value=d;j(e,c);c=h(e,c);if(b!="button")if(f)c.size||a(e).css({width:"98%"});else if(!c.size)c.size=20;a(e).attr("role",k);break;case "image":case "file":e=document.createElement("input");e.type=b;j(e,c);c=h(e,c);break;case "custom":e=document.createElement("span");try{if(a.isFunction(c.custom_element))if(m=c.custom_element.call(this,d,c)){m=a(m).addClass("customelement").attr({id:c.id,name:c.name});a(e).empty().append(m)}else throw"e2";
+else throw"e1";}catch(q){q=="e1"&&this.info_dialog(a.jgrid.errors.errcap,"function 'custom_element' "+a.jgrid.edit.msg.nodefined,a.jgrid.edit.bClose);q=="e2"?this.info_dialog(a.jgrid.errors.errcap,"function 'custom_element' "+a.jgrid.edit.msg.novalue,a.jgrid.edit.bClose):this.info_dialog(a.jgrid.errors.errcap,typeof q==="string"?q:q.message,a.jgrid.edit.bClose)}}return e},checkDate:function(b,c){var d={},f;b=b.toLowerCase();f=b.indexOf("/")!=-1?"/":b.indexOf("-")!=-1?"-":b.indexOf(".")!=-1?".":"/";
+b=b.split(f);c=c.split(f);if(c.length!=3)return false;f=-1;for(var g,h=-1,j=-1,e=0;e<b.length;e++){g=isNaN(c[e])?0:parseInt(c[e],10);d[b[e]]=g;g=b[e];if(g.indexOf("y")!=-1)f=e;if(g.indexOf("m")!=-1)j=e;if(g.indexOf("d")!=-1)h=e}g=b[f]=="y"||b[f]=="yyyy"?4:b[f]=="yy"?2:-1;e=function(m){for(var i=1;i<=m;i++){this[i]=31;if(i==4||i==6||i==9||i==11)this[i]=30;if(i==2)this[i]=29}return this}(12);var k;if(f===-1)return false;else{k=d[b[f]].toString();if(g==2&&k.length==1)g=1;if(k.length!=g||d[b[f]]===0&&
+c[f]!="00")return false}if(j===-1)return false;else{k=d[b[j]].toString();if(k.length<1||d[b[j]]<1||d[b[j]]>12)return false}if(h===-1)return false;else{k=d[b[h]].toString();if(k.length<1||d[b[h]]<1||d[b[h]]>31||d[b[j]]==2&&d[b[h]]>(d[b[f]]%4===0&&(d[b[f]]%100!==0||d[b[f]]%400===0)?29:28)||d[b[h]]>e[d[b[j]]])return false}return true},isEmpty:function(b){return b.match(/^\s+$/)||b===""?true:false},checkTime:function(b){var c=/^(\d{1,2}):(\d{2})([ap]m)?$/;if(!this.isEmpty(b))if(b=b.match(c)){if(b[3]){if(b[1]<
+1||b[1]>12)return false}else if(b[1]>23)return false;if(b[2]>59)return false}else return false;return true},checkValues:function(b,c,d,f,g){var h,j;if(typeof f==="undefined")if(typeof c=="string"){f=0;for(g=d.p.colModel.length;f<g;f++)if(d.p.colModel[f].name==c){h=d.p.colModel[f].editrules;c=f;try{j=d.p.colModel[f].formoptions.label}catch(e){}break}}else{if(c>=0)h=d.p.colModel[c].editrules}else{h=f;j=g===undefined?"_":g}if(h){j||(j=d.p.colNames[c]);if(h.required===true)if(this.isEmpty(b))return[false,
+j+": "+a.jgrid.edit.msg.required,""];f=h.required===false?false:true;if(h.number===true)if(!(f===false&&this.isEmpty(b)))if(isNaN(b))return[false,j+": "+a.jgrid.edit.msg.number,""];if(typeof h.minValue!="undefined"&&!isNaN(h.minValue))if(parseFloat(b)<parseFloat(h.minValue))return[false,j+": "+a.jgrid.edit.msg.minValue+" "+h.minValue,""];if(typeof h.maxValue!="undefined"&&!isNaN(h.maxValue))if(parseFloat(b)>parseFloat(h.maxValue))return[false,j+": "+a.jgrid.edit.msg.maxValue+" "+h.maxValue,""];if(h.email===
+true)if(!(f===false&&this.isEmpty(b))){g=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i;
+if(!g.test(b))return[false,j+": "+a.jgrid.edit.msg.email,""]}if(h.integer===true)if(!(f===false&&this.isEmpty(b))){if(isNaN(b))return[false,j+": "+a.jgrid.edit.msg.integer,""];if(b%1!==0||b.indexOf(".")!=-1)return[false,j+": "+a.jgrid.edit.msg.integer,""]}if(h.date===true)if(!(f===false&&this.isEmpty(b))){c=d.p.colModel[c].formatoptions&&d.p.colModel[c].formatoptions.newformat?d.p.colModel[c].formatoptions.newformat:d.p.colModel[c].datefmt||"Y-m-d";if(!this.checkDate(c,b))return[false,j+": "+a.jgrid.edit.msg.date+
+" - "+c,""]}if(h.time===true)if(!(f===false&&this.isEmpty(b)))if(!this.checkTime(b))return[false,j+": "+a.jgrid.edit.msg.date+" - hh:mm (am/pm)",""];if(h.url===true)if(!(f===false&&this.isEmpty(b))){g=/^(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;if(!g.test(b))return[false,j+": "+a.jgrid.edit.msg.url,""]}if(h.custom===true)if(!(f===false&&this.isEmpty(b)))if(a.isFunction(h.custom_func)){b=h.custom_func.call(d,b,j);return a.isArray(b)?
+b:[false,a.jgrid.edit.msg.customarray,""]}else return[false,a.jgrid.edit.msg.customfcheck,""]}return[true,"",""]}})})(jQuery);
+(function(b){b.jgrid.extend({jqGridImport:function(a){a=b.extend({imptype:"xml",impstring:"",impurl:"",mtype:"GET",impData:{},xmlGrid:{config:"roots>grid",data:"roots>rows"},jsonGrid:{config:"grid",data:"data"},ajaxOptions:{}},a||{});return this.each(function(){var d=this,c=function(f,g){var e=b(g.xmlGrid.config,f)[0],h=b(g.xmlGrid.data,f)[0],i;if(xmlJsonClass.xml2json&&b.jgrid.parse){e=xmlJsonClass.xml2json(e," ");e=b.jgrid.parse(e);for(var l in e)if(e.hasOwnProperty(l))i=e[l];if(h){h=e.grid.datatype;
+e.grid.datatype="xmlstring";e.grid.datastr=f;b(d).jqGrid(i).jqGrid("setGridParam",{datatype:h})}else b(d).jqGrid(i)}else alert("xml2json or parse are not present")},j=function(f,g){if(f&&typeof f=="string"){var e=b.jgrid.parse(f),h=e[g.jsonGrid.config];if(e=e[g.jsonGrid.data]){var i=h.datatype;h.datatype="jsonstring";h.datastr=e;b(d).jqGrid(h).jqGrid("setGridParam",{datatype:i})}else b(d).jqGrid(h)}};switch(a.imptype){case "xml":b.ajax(b.extend({url:a.impurl,type:a.mtype,data:a.impData,dataType:"xml",
+complete:function(f,g){if(g=="success"){c(f.responseXML,a);b.isFunction(a.importComplete)&&a.importComplete(f)}}},a.ajaxOptions));break;case "xmlstring":if(a.impstring&&typeof a.impstring=="string"){var k=b.jgrid.stringToDoc(a.impstring);if(k){c(k,a);b.isFunction(a.importComplete)&&a.importComplete(k);a.impstring=null}k=null}break;case "json":b.ajax(b.extend({url:a.impurl,type:a.mtype,data:a.impData,dataType:"json",complete:function(f,g){if(g=="success"){j(f.responseText,a);b.isFunction(a.importComplete)&&
+a.importComplete(f)}}},a.ajaxOptions));break;case "jsonstring":if(a.impstring&&typeof a.impstring=="string"){j(a.impstring,a);b.isFunction(a.importComplete)&&a.importComplete(a.impstring);a.impstring=null}}})},jqGridExport:function(a){a=b.extend({exptype:"xmlstring",root:"grid",ident:"\t"},a||{});var d=null;this.each(function(){if(this.grid){var c=b.extend({},b(this).jqGrid("getGridParam"));if(c.rownumbers){c.colNames.splice(0,1);c.colModel.splice(0,1)}if(c.multiselect){c.colNames.splice(0,1);c.colModel.splice(0,
+1)}if(c.subGrid){c.colNames.splice(0,1);c.colModel.splice(0,1)}c.knv=null;if(c.treeGrid)for(var j in c.treeReader)if(c.treeReader.hasOwnProperty(j)){c.colNames.splice(c.colNames.length-1);c.colModel.splice(c.colModel.length-1)}switch(a.exptype){case "xmlstring":d="<"+a.root+">"+xmlJsonClass.json2xml(c,a.ident)+"</"+a.root+">";break;case "jsonstring":d="{"+xmlJsonClass.toJson(c,a.root,a.ident,false)+"}";if(c.postData.filters!==undefined){d=d.replace(/filters":"/,'filters":');d=d.replace(/}]}"/,"}]}")}}}});
+return d},excelExport:function(a){a=b.extend({exptype:"remote",url:null,oper:"oper",tag:"excel",exportOptions:{}},a||{});return this.each(function(){if(this.grid){var d;if(a.exptype=="remote"){d=b.extend({},this.p.postData);d[a.oper]=a.tag;d=jQuery.param(d);d=a.url.indexOf("?")!=-1?a.url+"&"+d:a.url+"?"+d;window.location=d}}})}})})(jQuery);
+var xmlJsonClass={xml2json:function(a,b){if(a.nodeType===9)a=a.documentElement;var g=this.toJson(this.toObj(this.removeWhite(a)),a.nodeName,"\t");return"{\n"+b+(b?g.replace(/\t/g,b):g.replace(/\t|\n/g,""))+"\n}"},json2xml:function(a,b){var g=function(d,c,i){var h="",k,j;if(d instanceof Array)if(d.length===0)h+=i+"<"+c+">__EMPTY_ARRAY_</"+c+">\n";else{k=0;for(j=d.length;k<j;k+=1){var l=i+g(d[k],c,i+"\t")+"\n";h+=l}}else if(typeof d==="object"){k=false;h+=i+"<"+c;for(j in d)if(d.hasOwnProperty(j))if(j.charAt(0)===
+"@")h+=" "+j.substr(1)+'="'+d[j].toString()+'"';else k=true;h+=k?">":"/>";if(k){for(j in d)if(d.hasOwnProperty(j))if(j==="#text")h+=d[j];else if(j==="#cdata")h+="<![CDATA["+d[j]+"]]\>";else if(j.charAt(0)!=="@")h+=g(d[j],j,i+"\t");h+=(h.charAt(h.length-1)==="\n"?i:"")+"</"+c+">"}}else h+=typeof d==="function"?i+"<"+c+"><![CDATA["+d+"]]\></"+c+">":d.toString()==='""'||d.toString().length===0?i+"<"+c+">__EMPTY_STRING_</"+c+">":i+"<"+c+">"+d.toString()+"</"+c+">";return h},e="",f;for(f in a)if(a.hasOwnProperty(f))e+=
+g(a[f],f,"");return b?e.replace(/\t/g,b):e.replace(/\t|\n/g,"")},toObj:function(a){var b={},g=/function/i;if(a.nodeType===1){if(a.attributes.length){var e;for(e=0;e<a.attributes.length;e+=1)b["@"+a.attributes[e].nodeName]=(a.attributes[e].nodeValue||"").toString()}if(a.firstChild){var f=e=0,d=false,c;for(c=a.firstChild;c;c=c.nextSibling)if(c.nodeType===1)d=true;else if(c.nodeType===3&&c.nodeValue.match(/[^ \f\n\r\t\v]/))e+=1;else if(c.nodeType===4)f+=1;if(d)if(e<2&&f<2){this.removeWhite(a);for(c=
+a.firstChild;c;c=c.nextSibling)if(c.nodeType===3)b["#text"]=this.escape(c.nodeValue);else if(c.nodeType===4)if(g.test(c.nodeValue))b[c.nodeName]=[b[c.nodeName],c.nodeValue];else b["#cdata"]=this.escape(c.nodeValue);else if(b[c.nodeName])if(b[c.nodeName]instanceof Array)b[c.nodeName][b[c.nodeName].length]=this.toObj(c);else b[c.nodeName]=[b[c.nodeName],this.toObj(c)];else b[c.nodeName]=this.toObj(c)}else if(a.attributes.length)b["#text"]=this.escape(this.innerXml(a));else b=this.escape(this.innerXml(a));
+else if(e)if(a.attributes.length)b["#text"]=this.escape(this.innerXml(a));else{b=this.escape(this.innerXml(a));if(b==="__EMPTY_ARRAY_")b="[]";else if(b==="__EMPTY_STRING_")b=""}else if(f)if(f>1)b=this.escape(this.innerXml(a));else for(c=a.firstChild;c;c=c.nextSibling)if(g.test(a.firstChild.nodeValue)){b=a.firstChild.nodeValue;break}else b["#cdata"]=this.escape(c.nodeValue)}if(!a.attributes.length&&!a.firstChild)b=null}else if(a.nodeType===9)b=this.toObj(a.documentElement);else alert("unhandled node type: "+
+a.nodeType);return b},toJson:function(a,b,g,e){if(e===undefined)e=true;var f=b?'"'+b+'"':"",d="\t",c="\n";if(!e)c=d="";if(a==="[]")f+=b?":[]":"[]";else if(a instanceof Array){var i,h,k=[];h=0;for(i=a.length;h<i;h+=1)k[h]=this.toJson(a[h],"",g+d,e);f+=(b?":[":"[")+(k.length>1?c+g+d+k.join(","+c+g+d)+c+g:k.join(""))+"]"}else if(a===null)f+=(b&&":")+"null";else if(typeof a==="object"){i=[];for(h in a)if(a.hasOwnProperty(h))i[i.length]=this.toJson(a[h],h,g+d,e);f+=(b?":{":"{")+(i.length>1?c+g+d+i.join(","+
+c+g+d)+c+g:i.join(""))+"}"}else f+=typeof a==="string"?(b&&":")+'"'+a.replace(/\\/g,"\\\\").replace(/\"/g,'\\"')+'"':(b&&":")+'"'+a.toString()+'"';return f},innerXml:function(a){var b="";if("innerHTML"in a)b=a.innerHTML;else{var g=function(e){var f="",d;if(e.nodeType===1){f+="<"+e.nodeName;for(d=0;d<e.attributes.length;d+=1)f+=" "+e.attributes[d].nodeName+'="'+(e.attributes[d].nodeValue||"").toString()+'"';if(e.firstChild){f+=">";for(d=e.firstChild;d;d=d.nextSibling)f+=g(d);f+="</"+e.nodeName+">"}else f+=
+"/>"}else if(e.nodeType===3)f+=e.nodeValue;else if(e.nodeType===4)f+="<![CDATA["+e.nodeValue+"]]\>";return f};for(a=a.firstChild;a;a=a.nextSibling)b+=g(a)}return b},escape:function(a){return a.replace(/[\\]/g,"\\\\").replace(/[\"]/g,'\\"').replace(/[\n]/g,"\\n").replace(/[\r]/g,"\\r")},removeWhite:function(a){a.normalize();var b;for(b=a.firstChild;b;)if(b.nodeType===3)if(b.nodeValue.match(/[^ \f\n\r\t\v]/))b=b.nextSibling;else{var g=b.nextSibling;a.removeChild(b);b=g}else{b.nodeType===1&&this.removeWhite(b);
+b=b.nextSibling}return a}};
+(function(a){if(a.browser.msie&&a.browser.version==8)a.expr[":"].hidden=function(b){return b.offsetWidth===0||b.offsetHeight===0||b.style.display=="none"};a.jgrid._multiselect=false;if(a.ui)if(a.ui.multiselect){if(a.ui.multiselect.prototype._setSelected){var q=a.ui.multiselect.prototype._setSelected;a.ui.multiselect.prototype._setSelected=function(b,g){var c=q.call(this,b,g);if(g&&this.selectedList){var f=this.element;this.selectedList.find("li").each(function(){a(this).data("optionLink")&&a(this).data("optionLink").remove().appendTo(f)})}return c}}if(a.ui.multiselect.prototype.destroy)a.ui.multiselect.prototype.destroy=
+function(){this.element.show();this.container.remove();a.Widget===undefined?a.widget.prototype.destroy.apply(this,arguments):a.Widget.prototype.destroy.apply(this,arguments)};a.jgrid._multiselect=true}a.jgrid.extend({sortableColumns:function(b){return this.each(function(){function g(){c.p.disableClick=true}var c=this,f=c.p.id;f={tolerance:"pointer",axis:"x",scrollSensitivity:"1",items:">th:not(:has(#jqgh_"+f+"_cb,#jqgh_"+f+"_rn,#jqgh_"+f+"_subgrid),:hidden)",placeholder:{element:function(h){return a(document.createElement(h[0].nodeName)).addClass(h[0].className+
+" ui-sortable-placeholder ui-state-highlight").removeClass("ui-sortable-helper")[0]},update:function(h,j){j.height(h.currentItem.innerHeight()-parseInt(h.currentItem.css("paddingTop")||0,10)-parseInt(h.currentItem.css("paddingBottom")||0,10));j.width(h.currentItem.innerWidth()-parseInt(h.currentItem.css("paddingLeft")||0,10)-parseInt(h.currentItem.css("paddingRight")||0,10))}},update:function(h,j){var i=a(j.item).parent();i=a(">th",i);var l={},m=c.p.id+"_";a.each(c.p.colModel,function(k){l[this.name]=
+k});var d=[];i.each(function(){var k=a(">div",this).get(0).id.replace(/^jqgh_/,"").replace(m,"");k in l&&d.push(l[k])});a(c).jqGrid("remapColumns",d,true,true);a.isFunction(c.p.sortable.update)&&c.p.sortable.update(d);setTimeout(function(){c.p.disableClick=false},50)}};if(c.p.sortable.options)a.extend(f,c.p.sortable.options);else if(a.isFunction(c.p.sortable))c.p.sortable={update:c.p.sortable};if(f.start){var e=f.start;f.start=function(h,j){g();e.call(this,h,j)}}else f.start=g;if(c.p.sortable.exclude)f.items+=
+":not("+c.p.sortable.exclude+")";b.sortable(f).data("sortable").floating=true})},columnChooser:function(b){function g(d,k){if(d)if(typeof d=="string")a.fn[d]&&a.fn[d].apply(k,a.makeArray(arguments).slice(2));else a.isFunction(d)&&d.apply(k,a.makeArray(arguments).slice(2))}var c=this;if(!a("#colchooser_"+c[0].p.id).length){var f=a('<div id="colchooser_'+c[0].p.id+'" style="position:relative;overflow:hidden"><div><select multiple="multiple"></select></div></div>'),e=a("select",f);b=a.extend({width:420,
+height:240,classname:null,done:function(d){d&&c.jqGrid("remapColumns",d,true)},msel:"multiselect",dlog:"dialog",dlog_opts:function(d){var k={};k[d.bSubmit]=function(){d.apply_perm();d.cleanup(false)};k[d.bCancel]=function(){d.cleanup(true)};return{buttons:k,close:function(){d.cleanup(true)},modal:d.modal?d.modal:false,resizable:d.resizable?d.resizable:true,width:d.width+20}},apply_perm:function(){a("option",e).each(function(){this.selected?c.jqGrid("showCol",h[this.value].name):c.jqGrid("hideCol",
+h[this.value].name)});var d=[];a("option[selected]",e).each(function(){d.push(parseInt(this.value,10))});a.each(d,function(){delete i[h[parseInt(this,10)].name]});a.each(i,function(){var k=parseInt(this,10);var p=d,o=k;if(o>=0){var n=p.slice(),r=n.splice(o,Math.max(p.length-o,o));if(o>p.length)o=p.length;n[o]=k;d=n.concat(r)}else d=void 0});b.done&&b.done.call(c,d)},cleanup:function(d){g(b.dlog,f,"destroy");g(b.msel,e,"destroy");f.remove();d&&b.done&&b.done.call(c)},msel_opts:{}},a.jgrid.col,b||{});
+if(a.ui)if(a.ui.multiselect)if(b.msel=="multiselect"){if(!a.jgrid._multiselect){alert("Multiselect plugin loaded after jqGrid. Please load the plugin before the jqGrid!");return}b.msel_opts=a.extend(a.ui.multiselect.defaults,b.msel_opts)}b.caption&&f.attr("title",b.caption);if(b.classname){f.addClass(b.classname);e.addClass(b.classname)}if(b.width){a(">div",f).css({width:b.width,margin:"0 auto"});e.css("width",b.width)}if(b.height){a(">div",f).css("height",b.height);e.css("height",b.height-10)}var h=
+c.jqGrid("getGridParam","colModel"),j=c.jqGrid("getGridParam","colNames"),i={},l=[];e.empty();a.each(h,function(d){i[this.name]=d;if(this.hidedlg)this.hidden||l.push(d);else e.append("<option value='"+d+"' "+(this.hidden?"":"selected='selected'")+">"+j[d]+"</option>")});var m=a.isFunction(b.dlog_opts)?b.dlog_opts.call(c,b):b.dlog_opts;g(b.dlog,f,m);m=a.isFunction(b.msel_opts)?b.msel_opts.call(c,b):b.msel_opts;g(b.msel,e,m)}},sortableRows:function(b){return this.each(function(){var g=this;if(g.grid)if(!g.p.treeGrid)if(a.fn.sortable){b=
+a.extend({cursor:"move",axis:"y",items:".jqgrow"},b||{});if(b.start&&a.isFunction(b.start)){b._start_=b.start;delete b.start}else b._start_=false;if(b.update&&a.isFunction(b.update)){b._update_=b.update;delete b.update}else b._update_=false;b.start=function(c,f){a(f.item).css("border-width","0px");a("td",f.item).each(function(j){this.style.width=g.grid.cols[j].style.width});if(g.p.subGrid){var e=a(f.item).attr("id");try{a(g).jqGrid("collapseSubGridRow",e)}catch(h){}}b._start_&&b._start_.apply(this,
+[c,f])};b.update=function(c,f){a(f.item).css("border-width","");g.p.rownumbers===true&&a("td.jqgrid-rownum",g.rows).each(function(e){a(this).html(e+1)});b._update_&&b._update_.apply(this,[c,f])};a("tbody:first",g).sortable(b);a("tbody:first",g).disableSelection()}})},gridDnD:function(b){return this.each(function(){function g(){var e=a.data(c,"dnd");a("tr.jqgrow:not(.ui-draggable)",c).draggable(a.isFunction(e.drag)?e.drag.call(a(c),e):e.drag)}var c=this;if(c.grid)if(!c.p.treeGrid)if(a.fn.draggable&&
+a.fn.droppable){a("#jqgrid_dnd").html()===null&&a("body").append("<table id='jqgrid_dnd' class='ui-jqgrid-dnd'></table>");if(typeof b=="string"&&b=="updateDnD"&&c.p.jqgdnd===true)g();else{b=a.extend({drag:function(e){return a.extend({start:function(h,j){if(c.p.subGrid){var i=a(j.helper).attr("id");try{a(c).jqGrid("collapseSubGridRow",i)}catch(l){}}for(i=0;i<a.data(c,"dnd").connectWith.length;i++)a(a.data(c,"dnd").connectWith[i]).jqGrid("getGridParam","reccount")=="0"&&a(a.data(c,"dnd").connectWith[i]).jqGrid("addRowData",
+"jqg_empty_row",{});j.helper.addClass("ui-state-highlight");a("td",j.helper).each(function(m){this.style.width=c.grid.headers[m].width+"px"});e.onstart&&a.isFunction(e.onstart)&&e.onstart.call(a(c),h,j)},stop:function(h,j){if(j.helper.dropped){var i=a(j.helper).attr("id");a(c).jqGrid("delRowData",i)}for(i=0;i<a.data(c,"dnd").connectWith.length;i++)a(a.data(c,"dnd").connectWith[i]).jqGrid("delRowData","jqg_empty_row");e.onstop&&a.isFunction(e.onstop)&&e.onstop.call(a(c),h,j)}},e.drag_opts||{})},drop:function(e){return a.extend({accept:function(h){if(!a(h).hasClass("jqgrow"))return h;
+var j=a(h).closest("table.ui-jqgrid-btable");if(j.length>0&&a.data(j[0],"dnd")!==undefined){h=a.data(j[0],"dnd").connectWith;return a.inArray("#"+this.id,h)!=-1?true:false}return h},drop:function(h,j){if(a(j.draggable).hasClass("jqgrow")){var i=a(j.draggable).attr("id");i=j.draggable.parent().parent().jqGrid("getRowData",i);if(!e.dropbyname){var l=0,m={},d,k=a("#"+this.id).jqGrid("getGridParam","colModel");try{for(var p in i){if(i.hasOwnProperty(p)&&k[l]){d=k[l].name;m[d]=i[p]}l++}i=m}catch(o){}}j.helper.dropped=
+true;if(e.beforedrop&&a.isFunction(e.beforedrop)){d=e.beforedrop.call(this,h,j,i,a("#"+c.id),a(this));if(typeof d!="undefined"&&d!==null&&typeof d=="object")i=d}if(j.helper.dropped){var n;if(e.autoid)if(a.isFunction(e.autoid))n=e.autoid.call(this,i);else{n=Math.ceil(Math.random()*1E3);n=e.autoidprefix+n}a("#"+this.id).jqGrid("addRowData",n,i,e.droppos)}e.ondrop&&a.isFunction(e.ondrop)&&e.ondrop.call(this,h,j,i)}}},e.drop_opts||{})},onstart:null,onstop:null,beforedrop:null,ondrop:null,drop_opts:{activeClass:"ui-state-active",
+hoverClass:"ui-state-hover"},drag_opts:{revert:"invalid",helper:"clone",cursor:"move",appendTo:"#jqgrid_dnd",zIndex:5E3},dropbyname:false,droppos:"first",autoid:true,autoidprefix:"dnd_"},b||{});if(b.connectWith){b.connectWith=b.connectWith.split(",");b.connectWith=a.map(b.connectWith,function(e){return a.trim(e)});a.data(c,"dnd",b);c.p.reccount!="0"&&!c.p.jqgdnd&&g();c.p.jqgdnd=true;for(var f=0;f<b.connectWith.length;f++)a(b.connectWith[f]).droppable(a.isFunction(b.drop)?b.drop.call(a(c),b):b.drop)}}}})},
+gridResize:function(b){return this.each(function(){var g=this;if(g.grid&&a.fn.resizable){b=a.extend({},b||{});if(b.alsoResize){b._alsoResize_=b.alsoResize;delete b.alsoResize}else b._alsoResize_=false;if(b.stop&&a.isFunction(b.stop)){b._stop_=b.stop;delete b.stop}else b._stop_=false;b.stop=function(c,f){a(g).jqGrid("setGridParam",{height:a("#gview_"+g.p.id+" .ui-jqgrid-bdiv").height()});a(g).jqGrid("setGridWidth",f.size.width,b.shrinkToFit);b._stop_&&b._stop_.call(g,c,f)};b.alsoResize=b._alsoResize_?
+eval("("+("{'#gview_"+g.p.id+" .ui-jqgrid-bdiv':true,'"+b._alsoResize_+"':true}")+")"):a(".ui-jqgrid-bdiv","#gview_"+g.p.id);delete b._alsoResize_;a("#gbox_"+g.p.id).resizable(b)}})}})})(jQuery);
diff --git a/ishtar_common/static/media/images/favicon.png b/ishtar_common/static/media/images/favicon.png Binary files differnew file mode 100644 index 000000000..49a143457 --- /dev/null +++ b/ishtar_common/static/media/images/favicon.png diff --git a/ishtar_common/static/media/images/ishtar-bg.jpg b/ishtar_common/static/media/images/ishtar-bg.jpg Binary files differnew file mode 100644 index 000000000..f7802c576 --- /dev/null +++ b/ishtar_common/static/media/images/ishtar-bg.jpg diff --git a/ishtar_common/static/media/images/ishtar-text.png b/ishtar_common/static/media/images/ishtar-text.png Binary files differnew file mode 100644 index 000000000..34f3270eb --- /dev/null +++ b/ishtar_common/static/media/images/ishtar-text.png diff --git a/ishtar_common/static/media/images/logo.ico b/ishtar_common/static/media/images/logo.ico Binary files differnew file mode 100644 index 000000000..c6417a32e --- /dev/null +++ b/ishtar_common/static/media/images/logo.ico diff --git a/ishtar_common/static/media/images/logo.png b/ishtar_common/static/media/images/logo.png Binary files differnew file mode 100644 index 000000000..e150baa6c --- /dev/null +++ b/ishtar_common/static/media/images/logo.png diff --git a/ishtar_common/static/media/images/red_flag.png b/ishtar_common/static/media/images/red_flag.png Binary files differnew file mode 100644 index 000000000..20f50664e --- /dev/null +++ b/ishtar_common/static/media/images/red_flag.png diff --git a/ishtar_common/static/media/style.css b/ishtar_common/static/media/style.css new file mode 100644 index 000000000..ef58a1b0a --- /dev/null +++ b/ishtar_common/static/media/style.css @@ -0,0 +1,524 @@ +/* background color */ +.ui-widget-content .ui-state-highlight{ + background-color:#ff6e6e; +} + +/* color */ +a { + color:#D14; +} + + +body{ + font-family:Arial, Helvetica, sans-serif; + font-size: 11pt; + margin:0; + color:#61615C; + background-image:url(images/ishtar-bg.jpg); + background-repeat:no-repeat; + background-position:right top; +} + +a { + text-decoration:none; +} + +caption, h3 { + color:#922; + font-weight:bold; +} + +h3{ + text-align:center; + margin:1em 0 0.5em 0; +} + +label{display:block} + +label:first-letter { + text-transform: uppercase; +} + +textarea{ + height:80px; +} + +dt{ + font-weight:bold; + color:#922; + padding:1em; +} + +td{ + text-align:left; +} + +button{ + background-color:#EEE; + border:1px solid #AAA; + color:#444; +} + +input[type=submit], button.submit{ + background-color:#FFF; + border:1px solid #AAA; + color:#922; + margin:6px; +} + +button:hover, input[type=submit]:hover{ + cursor:pointer; +} + +.hidden{ + display:none; +} + +div#header{ + width:100%; + text-align:center; + font-size: 0.9em; + background-color: #EEE; + border-bottom:1px solid #CCC; + margin-bottom:10px; +} + +div#logo{ + width:200px; + top:30px; + left:30px; + padding-top:90px; + position:absolute; + text-align:center; + background-image:url(images/ishtar-text.png); + background-repeat:no-repeat; +} + +div#context_menu{ + height:110px; + margin-left:200px; + margin-right:20px; + margin-bottom:20px; +} + +div#main_menu{ + width:200px; + position:absolute; +} + +div#main_menu ul{ + padding-left:0.8em; + cursor:pointer; + list-style:none; +} + +div#main_menu a{ + color:#666; +} + +div#main_menu a:hover{ + color:#D14; +} + +div#main_menu .selected a{ + color:#D14; +} + + +div#main_menu > ul{ + color:#922; +} + +div#context_menu fieldset{ + right:20px; + position:absolute; + width:420px; + background-color:#EEE; + border:2px solid #CCC; + -moz-border-radius:8px; + -webkit-border-radius:8px; + border-radius:8px; +} +div#context_menu fieldset label{ + display:inline; +} + +div#context_menu ul{ + margin:0; + padding:2px; +} + +div#context_menu li{ + margin: 0; + list-style:none; +} + + +div#content{ + margin:0 200px; + text-align:center; +} + +ul#form_path{ + text-align:left; + margin:10px 0; +} + +ul#form_path li{ + display: inline; + text-align: center; + padding-left: 10px ; + margin: 0; + white-space:nowrap; +} + +ul#form_path li.current a{ + color:#922; +} + +ul#form_path button { + text-decoration:none; + color:#D14; + border:none; + background-color:white; + font-size: 1em; + cursor:pointer; + padding:0; + margin:0; + font-family:Arial, Helvetica, sans-serif; +} + +.reminder{ + padding:0.4em; + border:1px solid #CCC; + -moz-border-radius:8px; + -webkit-border-radius:8px; + border-radius:8px; + text-align:center; + width:400px; + margin-left:auto; + margin-right:auto; + background-color:white; +} + +div.form { + margin-left:auto; + margin-right:auto; + margin-bottom:40px; + padding:1em; + display:block; + width:740px; + background-color: #EEE; + border:2px solid #CCC; + -moz-border-radius:8px; + -webkit-border-radius:8px; + border-radius:8px; + text-align:center; +} + +.form table{ + padding:0.2em; + margin-left:auto; + margin-right:auto; + width:600px; +} + +.form table th{ + text-align:left; + width:200px; + font-weight:normal; +} + +.form .errorlist{ + color:#922; +} + +.form table .required th{ + font-weight:bold; +} + +.form input[readonly=True]{ + background-color:#EEE; + border:0; +} + +.help_text{ + display:none; + font-size:0.9em; +} + +.help_text div{ + background-color:#FFF; + margin:1em;; + padding:0 1em; + -moz-border-radius:8px; + -webkit-border-radius:8px; + border-radius:8px; + border:1px solid #AAA; +} + +.help_text .example{ + font-style:italic; +} + +.info{ + margin-left:auto; + margin-right:auto; + padding:1em; + display:block; + width:740px; +} + +.info p{ + padding:0; + margin:0.2em; +} + +.autocomplete{ + width:300px; +} + +.delete td{ + text-align:center; + border-bottom:1px solid #CCC; + padding:6px; +} + +.modify td, .submit td{ + text-align:center; +} + +div.form table.confirm{ + padding:0.5em 2em; + margin-left:0; + width:100%; +} + +table.confirm tr.spacer td:last-child{ + border-bottom:1px solid #922; +} + +/* jquery widget customizations */ + +.ui-autocomplete{ + font-size:0.7em +} + +.jqgrid{ + cursor:pointer; +} + +.ui-jqgrid a{ + color:red; + text-decoration:underline; + color:#D14; +} + +.ui-widget-content .ui-state-highlight{ + background-image:none; +} + +.sheet{ + width:760px; + position:fixed; + height:90%; + background: #FFF; + z-index: 2000; + left: 50%; + margin-left: -380px; + -webkit-box-shadow: 0px 0px 20px #444; + -moz-box-shadow: 0px 0px 20px #444; + text-align: left; + display:none; + -moz-border-radius:8px; + -webkit-border-radius:8px; + border-radius:8px; +} + +.dashboard > div{ + width:760px; + background: #FFF; + -moz-border-radius:8px; + -webkit-border-radius:8px; + border-radius:8px; + -webkit-box-shadow: 0px 0px 20px #444; + -moz-box-shadow: 0px 0px 20px #444; + margin:20px; + text-align:left; + padding-bottom:10px; +} + +.dashboard h3{ + background-color:#922; + color:#FFF; + -webkit-border-top-left-radius: 8px; + -webkit-border-top-right-radius: 8px; + -moz-border-radius-topleft: 8px; + -moz-border-radius-topright: 8px; + border-top-left-radius: 8px; + border-top-right-radius: 8px; +} + +.dashboard h4{ + font-weight:normal; + color:#D14; +} +.dashboard h4, .dashboard p{ + margin:0; + padding:0 10px; +} + +#window .table, .dashboard .table{ + padding:10px; + width:730px; + overflow:auto; +} + +#window table, .dashboard table{ + font-size:0.9em; + margin:10px 0; + border-collapse:collapse; + width:100%; +} + +#window caption, .dashboard caption{ + font-size:1.2em; +} + +#window table th, .dashboard table th{ + text-align:center; + background-color:#922; + border:1px solid #EEE; + color:#FFF; +} + +#window table th.sub, .dashboard table th.sub, .dashboard table td.sub{ + background-color:#994242; + border:1px solid #EEE; + color:#FFF; + padding:0 1em; +} + +#window table th.sub, .dashboard table th.sub{ + text-align:left; +} + +#window table td, .dashboard table td{ + text-align:right; + padding:0 1em; + border:1px solid #EEE; +} + +#window table td.string, .dashboard table td.string{ + text-align:left; +} + +#window table td.ref, .dashboard table td.ref{ + text-align:left; + white-space:nowrap; + font-family:monospace; + font-size:9pt; +} + +#window table td.no_items{ + text-align:center; + font-style:italic; +} + +#window .head{ + text-align:center; + background-color:#EEE; + -webkit-border-top-left-radius: 8px; + -webkit-border-top-right-radius: 8px; + -moz-border-radius-topleft: 8px; + -moz-border-radius-topright: 8px; + border-top-left-radius: 8px; + border-top-right-radius: 8px; +} + +#window .tool{ + text-align:center; + font-style:italic; +} + +#window .body{ + position:absolute; + padding:10px; + overflow:auto; + top:18px; + bottom:10px; + width:740px; +} + +#window label{ + display:inline-table; + font-weight:bold; + width:245px; +} + +#window span.value{ + display:inline-table; + width:465px; +} + +#window p{ + margin:0.3em; +} + +#window p.alert{ + color:#D14; + display:block; + font-style:italic; + width:670px; + padding:1em; + padding-left:2em; + background-color:#EEE; + -moz-border-radius:8px; + -webkit-border-radius:8px; + border-radius:8px; + background-image:url(images/red_flag.png); + background-repeat:no-repeat; + background-position:left center; +} + +#window p.alert label{ + width:650px; +} + +ul.selectmulti{ + list-style-type:none; + text-align:left; + margin-left:100px; +} + +ul.selectmulti li{ + margin:6px 0; +} + +td.submit_button{ + text-align:center; +} + +a.add-button, a.remove{ + background-color:#FFF; + border:2px solid #CCC; + -moz-border-radius:8px; + -webkit-border-radius:8px; + border-radius:8px; + padding:0 4px; + color:#61615C; +} + +a.remove{ + color:#D14; + margin:0 6px; +} + +.dashboard table{ + width:100%; + border-collapse:yes; +} +.dashboard table th, .dashboard table td{ + border:1px solid; +} + diff --git a/ishtar_common/static/media/style_basic.css b/ishtar_common/static/media/style_basic.css new file mode 100644 index 000000000..d624ae09c --- /dev/null +++ b/ishtar_common/static/media/style_basic.css @@ -0,0 +1,87 @@ +@page { + size: a4 portrait; + margin: 2.5cm 1cm 2.5cm 1cm; + background-image: url("images/ishtar-bg.jpg"); + @frame footer { + -pdf-frame-content: pdffooter; + bottom: 1cm; + margin-left: 1cm; + margin-right: 1cm; + height: 1cm; + } + @frame header { + -pdf-frame-content: pdfheader; + top: 1.2cm; + margin-left: 1cm; + margin-right: 1cm; + height: 1.5cm; + } +} + +label{ + display:inline; + font-weight:bold; +} + +table{ + margin:10px; + width:100%; + border: none; + border-collapse:collapse; +} + +caption, h3{ + display:block; + text-align:center; + font-size:1.5em; +} + +th{ + text-align:center; + border-bottom:2px solid #922; +} + +td{ + margin:0; + padding:0; + padding-top:4px; + text-align:right; + border:1px solid #EEE; + border-top:none; + font-size:0.9em; +} + +.link{ + display:None; +} + +.string{ + text-align:left; +} + +.no_items{ + text-align:center; + font-style:italic; +} + +.head{ + display:none; +} + +.tool{ + display:none; +} + +p{ + margin:0.2em; +} + +#pdffooter, #pdfheader{ + text-align:center; +} + +#pdfheader{ + font-weight:bold; + width:100%; + border-bottom:1px solid #922; +} diff --git a/ishtar_common/static/media/ui.jqgrid.css b/ishtar_common/static/media/ui.jqgrid.css new file mode 100644 index 000000000..e69018909 --- /dev/null +++ b/ishtar_common/static/media/ui.jqgrid.css @@ -0,0 +1,139 @@ +/*Grid*/
+.ui-jqgrid {position: relative; font-size:11px;}
+.ui-jqgrid .ui-jqgrid-view {position: relative;left:0px; top: 0px; padding: .0em;}
+/* caption*/
+.ui-jqgrid .ui-jqgrid-titlebar {padding: .3em .2em .2em .3em; position: relative; border-left: 0px none;border-right: 0px none; border-top: 0px none;}
+.ui-jqgrid .ui-jqgrid-title { float: left; margin: .1em 0 .2em; }
+.ui-jqgrid .ui-jqgrid-titlebar-close { position: absolute;top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height:18px;}.ui-jqgrid .ui-jqgrid-titlebar-close span { display: block; margin: 1px; }
+.ui-jqgrid .ui-jqgrid-titlebar-close:hover { padding: 0; }
+/* header*/
+.ui-jqgrid .ui-jqgrid-hdiv {position: relative; margin: 0em;padding: 0em; overflow-x: hidden; overflow-y: auto; border-left: 0px none !important; border-top : 0px none !important; border-right : 0px none !important;}
+.ui-jqgrid .ui-jqgrid-hbox {float: left; padding-right: 20px;}
+.ui-jqgrid .ui-jqgrid-htable {table-layout:fixed;margin:0em;}
+.ui-jqgrid .ui-jqgrid-htable th {height:22px;padding: 0 2px 0 2px;}
+.ui-jqgrid .ui-jqgrid-htable th div {overflow: hidden; position:relative; height:17px;}
+.ui-th-column, .ui-jqgrid .ui-jqgrid-htable th.ui-th-column {overflow: hidden;white-space: nowrap;text-align:center;border-top : 0px none;border-bottom : 0px none;}
+.ui-th-ltr, .ui-jqgrid .ui-jqgrid-htable th.ui-th-ltr {border-left : 0px none;}
+.ui-th-rtl, .ui-jqgrid .ui-jqgrid-htable th.ui-th-rtl {border-right : 0px none;}
+.ui-jqgrid .ui-th-div-ie {white-space: nowrap; zoom :1; height:17px;}
+.ui-jqgrid .ui-jqgrid-resize {height:20px !important;position: relative; cursor :e-resize;display: inline;overflow: hidden;}
+.ui-jqgrid .ui-grid-ico-sort {overflow:hidden;position:absolute;display:inline; cursor: pointer !important;}
+.ui-jqgrid .ui-icon-asc {margin-top:-3px; height:12px;}
+.ui-jqgrid .ui-icon-desc {margin-top:3px;height:12px;}
+.ui-jqgrid .ui-i-asc {margin-top:0px;height:16px;}
+.ui-jqgrid .ui-i-desc {margin-top:0px;margin-left:13px;height:16px;}
+.ui-jqgrid .ui-jqgrid-sortable {cursor:pointer;}
+.ui-jqgrid tr.ui-search-toolbar th { border-top-width: 1px !important; border-top-color: inherit !important; border-top-style: ridge !important }
+tr.ui-search-toolbar input {margin: 1px 0px 0px 0px}
+tr.ui-search-toolbar select {margin: 1px 0px 0px 0px}
+/* body */
+.ui-jqgrid .ui-jqgrid-bdiv {position: relative; margin: 0em; padding:0; overflow: auto; text-align:left;}
+.ui-jqgrid .ui-jqgrid-btable {table-layout:fixed; margin:0em;}
+.ui-jqgrid tr.jqgrow td {font-weight: normal; overflow: hidden; white-space: pre; height: 22px;padding: 0 2px 0 2px;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
+.ui-jqgrid tr.jqgfirstrow td {padding: 0 2px 0 2px;border-right-width: 1px; border-right-style: solid;}
+.ui-jqgrid tr.jqgroup td {font-weight: normal; overflow: hidden; white-space: pre; height: 22px;padding: 0 2px 0 2px;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
+.ui-jqgrid tr.jqfoot td {font-weight: bold; overflow: hidden; white-space: pre; height: 22px;padding: 0 2px 0 2px;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
+.ui-jqgrid tr.ui-row-ltr td {text-align:left;border-right-width: 1px; border-right-color: inherit; border-right-style: solid;}
+.ui-jqgrid tr.ui-row-rtl td {text-align:right;border-left-width: 1px; border-left-color: inherit; border-left-style: solid;}
+.ui-jqgrid td.jqgrid-rownum { padding: 0 2px 0 2px; margin: 0px; border: 0px none;}
+.ui-jqgrid .ui-jqgrid-resize-mark { width:2px; left:0; background-color:#777; cursor: e-resize; cursor: col-resize; position:absolute; top:0; height:100px; overflow:hidden; display:none; border:0 none;}
+/* footer */
+.ui-jqgrid .ui-jqgrid-sdiv {position: relative; margin: 0em;padding: 0em; overflow: hidden; border-left: 0px none !important; border-top : 0px none !important; border-right : 0px none !important;}
+.ui-jqgrid .ui-jqgrid-ftable {table-layout:fixed; margin-bottom:0em;}
+.ui-jqgrid tr.footrow td {font-weight: bold; overflow: hidden; white-space:nowrap; height: 21px;padding: 0 2px 0 2px;border-top-width: 1px; border-top-color: inherit; border-top-style: solid;}
+.ui-jqgrid tr.footrow-ltr td {text-align:left;border-right-width: 1px; border-right-color: inherit; border-right-style: solid;}
+.ui-jqgrid tr.footrow-rtl td {text-align:right;border-left-width: 1px; border-left-color: inherit; border-left-style: solid;}
+/* Pager*/
+.ui-jqgrid .ui-jqgrid-pager { border-left: 0px none !important;border-right: 0px none !important; border-bottom: 0px none !important; margin: 0px !important; padding: 0px !important; position: relative; height: 25px;white-space: nowrap;overflow: hidden;}
+.ui-jqgrid .ui-pager-control {position: relative;}
+.ui-jqgrid .ui-pg-table {position: relative; padding-bottom:2px; width:auto; margin: 0em;}
+.ui-jqgrid .ui-pg-table td {font-weight:normal; vertical-align:middle; padding:1px;}
+.ui-jqgrid .ui-pg-button { height:19px !important;}
+.ui-jqgrid .ui-pg-button span { display: block; margin: 1px; float:left;}
+.ui-jqgrid .ui-pg-button:hover { padding: 0px; }
+.ui-jqgrid .ui-state-disabled:hover {padding:1px;}
+.ui-jqgrid .ui-pg-input { height:13px;font-size:.8em; margin: 0em;}
+.ui-jqgrid .ui-pg-selbox {font-size:.8em; line-height:18px; display:block; height:18px; margin: 0em;}
+.ui-jqgrid .ui-separator {height: 18px; border-left: 1px solid #ccc ; border-right: 1px solid #ccc ; margin: 1px; float: right;}
+.ui-jqgrid .ui-paging-info {font-weight: normal;height:19px; margin-top:3px;margin-right:4px;}
+.ui-jqgrid .ui-jqgrid-pager .ui-pg-div {padding:1px 0;float:left;list-style-image:none;list-style-position:outside;list-style-type:none;position:relative;}
+.ui-jqgrid .ui-jqgrid-pager .ui-pg-button { cursor:pointer; }
+.ui-jqgrid .ui-jqgrid-pager .ui-pg-div span.ui-icon {float:left;margin:0 2px;}
+.ui-jqgrid td input, .ui-jqgrid td select .ui-jqgrid td textarea { margin: 0em;}
+.ui-jqgrid td textarea {width:auto;height:auto;}
+.ui-jqgrid .ui-jqgrid-toppager {border-left: 0px none !important;border-right: 0px none !important; border-top: 0px none !important; margin: 0px !important; padding: 0px !important; position: relative; height: 25px !important;white-space: nowrap;overflow: hidden;}
+/*subgrid*/
+.ui-jqgrid .ui-jqgrid-btable .ui-sgcollapsed span {display: block;}
+.ui-jqgrid .ui-subgrid {margin:0em;padding:0em; width:100%;}
+.ui-jqgrid .ui-subgrid table {table-layout: fixed;}
+.ui-jqgrid .ui-subgrid tr.ui-subtblcell td {height:18px;border-right-width: 1px; border-right-color: inherit; border-right-style: solid;border-bottom-width: 1px; border-bottom-color: inherit; border-bottom-style: solid;}
+.ui-jqgrid .ui-subgrid td.subgrid-data {border-top: 0px none !important;}
+.ui-jqgrid .ui-subgrid td.subgrid-cell {border-width: 0px 0px 1px 0px;}
+.ui-jqgrid .ui-th-subgrid {height:20px;}
+/* loading */
+.ui-jqgrid .loading {position: absolute; top: 45%;left: 45%;width: auto;z-index:101;padding: 6px; margin: 5px;text-align: center;font-weight: bold;display: none;border-width: 2px !important;}
+.ui-jqgrid .jqgrid-overlay {display:none;z-index:100;}
+* html .jqgrid-overlay {width: expression(this.parentNode.offsetWidth+'px');height: expression(this.parentNode.offsetHeight+'px');}
+* .jqgrid-overlay iframe {position:absolute;top:0;left:0;z-index:-1;width: expression(this.parentNode.offsetWidth+'px');height: expression(this.parentNode.offsetHeight+'px');}
+/* end loading div */
+/* toolbar */
+.ui-jqgrid .ui-userdata {border-left: 0px none; border-right: 0px none; height : 21px;overflow: hidden; }
+/*Modal Window */
+.ui-jqdialog { display: none; width: 300px; position: absolute; padding: .2em; font-size:11px; overflow:visible;}
+.ui-jqdialog .ui-jqdialog-titlebar { padding: .3em .2em; position: relative; }
+.ui-jqdialog .ui-jqdialog-title { margin: .1em 0 .2em; }
+.ui-jqdialog .ui-jqdialog-titlebar-close { position: absolute; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+
+.ui-jqdialog .ui-jqdialog-titlebar-close span { display: block; margin: 1px; }
+.ui-jqdialog .ui-jqdialog-titlebar-close:hover, .ui-jqdialog .ui-jqdialog-titlebar-close:focus { padding: 0; }
+.ui-jqdialog-content, .ui-jqdialog .ui-jqdialog-content { border: 0; padding: .3em .2em; background: none; height:auto;}
+.ui-jqdialog .ui-jqconfirm {padding: .4em 1em; border-width:3px;position:absolute;bottom:10px;right:10px;overflow:visible;display:none;height:80px;width:220px;text-align:center;}
+/* end Modal window*/
+/* Form edit */
+.ui-jqdialog-content .FormGrid {margin: 0px;}
+.ui-jqdialog-content .EditTable { width: 100%; margin-bottom:0em;}
+.ui-jqdialog-content .DelTable { width: 100%; margin-bottom:0em;}
+.EditTable td input, .EditTable td select, .EditTable td textarea {margin: 0em;}
+.EditTable td textarea { width:auto; height:auto;}
+.ui-jqdialog-content td.EditButton {text-align: right;border-top: 0px none;border-left: 0px none;border-right: 0px none; padding-bottom:5px; padding-top:5px;}
+.ui-jqdialog-content td.navButton {text-align: center; border-left: 0px none;border-top: 0px none;border-right: 0px none; padding-bottom:5px; padding-top:5px;}
+.ui-jqdialog-content input.FormElement {padding:.3em}
+.ui-jqdialog-content .data-line {padding-top:.1em;border: 0px none;}
+
+.ui-jqdialog-content .CaptionTD {text-align: left; vertical-align: middle;border: 0px none; padding: 2px;white-space: nowrap;}
+.ui-jqdialog-content .DataTD {padding: 2px; border: 0px none; vertical-align: top;}
+.ui-jqdialog-content .form-view-data {white-space:pre}
+.fm-button { display: inline-block; margin:0 4px 0 0; padding: .4em .5em; text-decoration:none !important; cursor:pointer; position: relative; text-align: center; zoom: 1; }
+.fm-button-icon-left { padding-left: 1.9em; }
+.fm-button-icon-right { padding-right: 1.9em; }
+.fm-button-icon-left .ui-icon { right: auto; left: .2em; margin-left: 0; position: absolute; top: 50%; margin-top: -8px; }
+.fm-button-icon-right .ui-icon { left: auto; right: .2em; margin-left: 0; position: absolute; top: 50%; margin-top: -8px;}
+#nData, #pData { float: left; margin:3px;padding: 0; width: 15px; }
+/* End Eorm edit */
+/*.ui-jqgrid .edit-cell {}*/
+.ui-jqgrid .selected-row, div.ui-jqgrid .selected-row td {font-style : normal;border-left: 0px none;}
+/* Tree Grid */
+.ui-jqgrid .tree-wrap {float: left; position: relative;height: 18px;white-space: nowrap;overflow: hidden;}
+.ui-jqgrid .tree-minus {position: absolute; height: 18px; width: 18px; overflow: hidden;}
+.ui-jqgrid .tree-plus {position: absolute; height: 18px; width: 18px; overflow: hidden;}
+.ui-jqgrid .tree-leaf {position: absolute; height: 18px; width: 18px;overflow: hidden;}
+.ui-jqgrid .treeclick {cursor: pointer;}
+/* moda dialog */
+.jqmOverlay { background-color: #000; }
+* iframe.jqm {position:absolute;top:0;left:0;z-index:-1;width: expression(this.parentNode.offsetWidth+'px');height: expression(this.parentNode.offsetHeight+'px');}
+.ui-jqgrid-dnd tr td {border-right-width: 1px; border-right-color: inherit; border-right-style: solid; height:20px}
+/* RTL Support */
+.ui-jqgrid .ui-jqgrid-title-rtl {float:right;margin: .1em 0 .2em; }
+.ui-jqgrid .ui-jqgrid-hbox-rtl {float: right; padding-left: 20px;}
+.ui-jqgrid .ui-jqgrid-resize-ltr {float: right;margin: -2px -2px -2px 0px;}
+.ui-jqgrid .ui-jqgrid-resize-rtl {float: left;margin: -2px 0px -1px -3px;}
+.ui-jqgrid .ui-sort-rtl {left:0px;}
+.ui-jqgrid .tree-wrap-ltr {float: left;}
+.ui-jqgrid .tree-wrap-rtl {float: right;}
+.ui-jqgrid .ui-ellipsis {text-overflow:ellipsis; -moz-binding:url('ellipsis-xbl.xml#ellipsis');}
+.ui-searchFilter { display: none; position: absolute; z-index: 770; overflow: visible;}
+.ui-searchFilter table {position:relative; margin:0em; width:auto}
+.ui-searchFilter table td {margin: 0em; padding: 1px;}
+.ui-searchFilter table td input, .ui-searchFilter table td select {margin: 0.1em;}
+.ui-searchFilter .ui-state-default { cursor: pointer; }
+.ui-searchFilter .divider hr {margin: 1px; }
\ No newline at end of file diff --git a/ishtar_common/static/template.odt b/ishtar_common/static/template.odt Binary files differnew file mode 100644 index 000000000..d1d0515bf --- /dev/null +++ b/ishtar_common/static/template.odt diff --git a/ishtar_common/templates/account_activation_email.txt b/ishtar_common/templates/account_activation_email.txt new file mode 100644 index 000000000..2dcc77d3e --- /dev/null +++ b/ishtar_common/templates/account_activation_email.txt @@ -0,0 +1,13 @@ +{% load i18n %} + +{% blocktrans %}Your account on {{app_name}} has been created or modified.{% endblocktrans %} + + * {% trans "Login:" %} {{login}} + * {% trans "Password:" %} {{password}} + +{% trans "You can log in here:" %} http://{{site}}{%url auth_login%} + +{% trans "Thank you for you interest in the project." %} + +-- +{% blocktrans %}The {{app_name}} team{% endblocktrans %} diff --git a/ishtar_common/templates/admin/base_site.html b/ishtar_common/templates/admin/base_site.html new file mode 100644 index 000000000..3282d4f5a --- /dev/null +++ b/ishtar_common/templates/admin/base_site.html @@ -0,0 +1,10 @@ +{% extends "admin/base.html" %} +{% load i18n %} + +{% block title %}{{ title }} | {% trans 'Ishtar administration' %}{% endblock %} + +{% block branding %} +<h1 id="site-name">{% trans 'Ishtar administration' %}</h1> +{% endblock %} + +{% block nav-global %}{% endblock %} diff --git a/ishtar_common/templates/base.html b/ishtar_common/templates/base.html new file mode 100644 index 000000000..630fe666e --- /dev/null +++ b/ishtar_common/templates/base.html @@ -0,0 +1,89 @@ +{% load i18n %} +<!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> + <link rel="shortcut icon" href="{{MEDIA_URL}}/media/images/favicon.png"/> + <title>{% block title %}Ishtar{% if APP_NAME %} - {{APP_NAME}}{%endif%}{% endblock %} + </title> + <script language="javascript" type="text/javascript"> + var url_path = "{{URL_PATH}}"; + </script> + <script language="javascript" type="text/javascript" src="{{JQUERY_URL}}"></script> + <script language="javascript" type="text/javascript" src="{{JQUERY_UI_URL}}jquery-ui.js"></script> + <script language="javascript" type="text/javascript" src="{{JQUERY_UI_URL}}ui/i18n/jquery.ui.datepicker-{{COUNTRY}}.js"></script> + <script language="javascript" type="text/javascript" src="{{MEDIA_URL}}/js/ishtar.js"></script> + <link type="text/css" href="{{JQUERY_UI_URL}}css/smoothness/jquery-ui.css" rel="stylesheet" /> + <link rel="stylesheet" href="{{MEDIA_URL}}/media/style.css" /> + {% block extra_head %} + {% endblock %} +</head> +<body> + <div id="header"> + {% block header %} + {% if user.is_authenticated %} + {% trans "Logged in" %}: {{ user.username }} + (<a href="{% url auth_logout %}">{% trans "Log out" %}</a> | + <a href="{% url auth_password_change %}">{% trans "Change password" %}</a>) + {% else %} + <strong><a href="{% url auth_login %}">{% trans "Log in" %}</a></strong> + {% endif %} + {% endblock %} + </div> + <div id="window"></div> + <div id="logo"> +{% if APP_NAME %}<p id="app_name">{{APP_NAME}}</p>{%endif%} + </div> + <div id="context_menu"> + {% block context %}{% if current_menu %} + <form method="post" action="{% url update-current-item %}"> + <fieldset> + <legend>{% trans "Default items"%}</legend> + <table id='current_items'> + {% for lbl, model_name, items in current_menu %} + <tr> + <td><label for="current_{{model_name}}">{{lbl}}</label></td> + <td> + <select id='current_{{model_name}}'> + <option value=''>--</option> + {% for val, label, selected in items %}<option value='{{val}}'{%if selected%} selected="selected"{%endif%}>{{label}}</option> + {% endfor %}</select> + </td> + </tr> + {% endfor %} + </table> + </fieldset> + </form> + {% endif %}{% endblock %} + </div> + <div id="main_menu"> + <ul> + {% for section in MENU.childs %} + {% if section.available %}<li>{{section.label}} + <ul> + {% for menu_item in section.childs %}{%if menu_item.available%} + {% if menu_item.childs %}<li>{{menu_item.label}} + <ul> + {% for menu_subitem in menu_item.childs %}{%if menu_subitem.available%} + <li{%ifequal menu_subitem.idx CURRENT_ACTION%} class='selected'{%endifequal%}><a href='{% url action menu_subitem.idx%}'>{{menu_subitem.label}}</a></li> + {%endif%}{% endfor %}</ul></li> + {%else%} + <li{%ifequal menu_item.idx CURRENT_ACTION%} class='selected'{%endifequal%}><a href='{% url action menu_item.idx%}'>{{menu_item.label}}</a></li> + {%endif%}{% endif %}{% endfor %} + </ul> + </li>{%endif%} + {% endfor %} + </ul> + </div> + <div id="content"> + {% block content %}{% endblock %} + </div> + + <div id="footer"> + {% block footer %} + {% endblock %} + </div> +</body> + +</html> diff --git a/ishtar_common/templates/dashboard_file.html b/ishtar_common/templates/dashboard_file.html new file mode 100644 index 000000000..cebd147f4 --- /dev/null +++ b/ishtar_common/templates/dashboard_file.html @@ -0,0 +1,215 @@ +{% extends "base.html" %} +{% load i18n %} +{% load range %} +{% block extra_head %} +{{form.media}} +{% endblock %} +{% block content %} +<div class='dashboard'> + <h2>{% trans "Archaeological files" %}</h2> + <div> + <h3>{% trans "Global informations" %}</h3> + + <p><strong>{% trans "Total:" %}</strong> {{dashboard.total_number}}</p> + {% for type in dashboard.types %} + <p><strong>{{type.file_type__label}}{% trans ":"%}</strong> {{type.number}}</p> + {% endfor %} + <div class='table'> + <table> + <caption>{% trans "By year"%}</caption> + <tr> + {% for year in dashboard.by_year %}<th>{{year.date.year}}</th>{% endfor %} + </tr> + <tr> + {% for year in dashboard.by_year %}<td>{{year.number}}</td>{% endfor%} + </tr> + </table> + </div> + + <div class='table'> + <table> + <caption>{% trans "By month"%}</caption> + <tr> + {% for month in dashboard.by_month %}<th>{{month.date|date:"F Y"|capfirst}}</th>{% endfor %} + </tr> + <tr> + {% for month in dashboard.by_month %}<td>{{month.number}}</td>{% endfor%} + </tr> + </table> + </div> + + </div> + <div> + + <h3>{% trans "Research archaeology" %}</h3> + + <p><strong>{% trans "Total:" %}</strong> {{dashboard.research.total_number}}</p> + <div class='table'> + <table> + <caption>{% trans "By year"%}</caption> + <tr> + {% for year in dashboard.research.by_year %}<th>{{year.date.year}}</th>{% endfor %} + </tr> + <tr> + {% for year in dashboard.research.by_year %}<td>{{year.number}}</td>{% endfor%} + </tr> + </table> + </div> + + <div class='table'> + <table> + <caption>{% trans "By month"%}</caption> + <tr> + {% for month in dashboard.research.by_month %}<th>{{month.date|date:"F Y"|capfirst}}</th>{% endfor %} + </tr> + <tr> + {% for month in dashboard.research.by_month %}<td>{{month.number}}</td>{% endfor%} + </tr> + </table> + </div> + + <div class='table'> + <table> + <caption>{% trans "By department"%}</caption> + <tr> + {% for dpt in dashboard.research.by_dpt %}<th>{{dpt.department__label}}</th>{% endfor %} + </tr> + <tr> + {% for dpt in dashboard.research.by_dpt %}<td>{{dpt.number}}</td>{% endfor%} + </tr> + </table> + </div> + + <div class='table'> + <table> + <caption>{% trans "Main towns"%}</caption> + <tr> + {% for town in dashboard.research.towns %}<th>{{town.town__name}}</th>{% endfor %} + </tr> + <tr> + {% for town in dashboard.research.towns %}<td>{{town.number}}</td>{% endfor%} + </tr> + </table> + </div> + + </div> + <div> + + <h3>{% trans "Rescue archaeology" %}</h3> + + <p><strong>{% trans "Total:" %}</strong> {{dashboard.rescue.total_number}}</p> + + <div class='table'> + <table> + <caption>{% trans "By saisine type"%}</caption> + <tr> + {% for saisine in dashboard.rescue.saisine %}<th>{{saisine.saisine_type__label}}</th>{% endfor %} + </tr> + <tr> + {% for saisine in dashboard.rescue.saisine %}<td>{{saisine.number}}</td>{% endfor%} + </tr> + </table> + </div> + + <div class='table'> + <table> + <caption>{% trans "By administrative act"%}</caption> + <tr> + {% for act in dashboard.rescue.administrative_act %}<th>{{act.act_type__label}}</th>{% endfor %} + </tr> + <tr> + {% for act in dashboard.rescue.administrative_act %}<td>{{act.number}}</td>{% endfor%} + </tr> + </table> + </div> + + <div class='table'> + <table> + <caption>{% trans "By year"%}</caption> + <tr> + {% for year in dashboard.rescue.by_year %}<th>{{year.date.year}}</th>{% endfor %} + </tr> + <tr> + {% for year in dashboard.rescue.by_year %}<td>{{year.number}}</td>{% endfor%} + </tr> + </table> + </div> + + <div class='table'> + <table> + <caption>{% trans "By month"%}</caption> + <tr> + {% for month in dashboard.rescue.by_month %}<th>{{month.date|date:"F Y"|capfirst}}</th>{% endfor %} + </tr> + <tr> + {% for month in dashboard.rescue.by_month %}<td>{{month.number}}</td>{% endfor%} + </tr> + </table> + </div> + + <p><strong>{% trans "Archaeological files linked to at least one operation:" %}</strong> {{dashboard.rescue.with_associated_operation}}</p> + <p><strong>{% trans "Archaeological files linked to at least one operation (%):" %}</strong> {{dashboard.rescue.with_associated_operation_percent}}</p> + + <div class='table'> + <table> + <caption>{% trans "Archaeological files linked to at least one operation (%)"%}</caption> + <tr> + {% for year in dashboard.rescue.operational_by_year %}<th>{{year.date.year}}</th>{% endfor %} + </tr> + <tr> + {% for year in dashboard.rescue.operational_by_year %}<td>{{year.number}}</td>{% endfor%} + </tr> + </table> + </div> + + <div class='table'> + <table> + <caption>{% trans "By department"%}</caption> + <tr> + {% for dpt in dashboard.rescue.by_dpt %}<th>{{dpt.department__label}}</th>{% endfor %} + </tr> + <tr> + {% for dpt in dashboard.rescue.by_dpt %}<td>{{dpt.number}}</td>{% endfor%} + </tr> + </table> + </div> + + <div class='table'> + <table> + <caption>{% trans "Surface by department (m²)"%}</caption> + <tr> + {% for dpt in dashboard.rescue.surface_by_dpt %}<th>{{dpt.department__label}}</th>{% endfor %} + </tr> + <tr> + {% for dpt in dashboard.rescue.surface_by_dpt %}<td>{{dpt.number}}</td>{% endfor%} + </tr> + </table> + </div> + + <div class='table'> + <table> + <caption>{% trans "Main towns by number"%}</caption> + <tr> + {% for town in dashboard.rescue.towns %}<th>{{town.town__name}}</th>{% endfor %} + </tr> + <tr> + {% for town in dashboard.rescue.towns %}<td>{{town.number}}</td>{% endfor%} + </tr> + </table> + </div> + + <div class='table'> + <table> + <caption>{% trans "Main towns by surface (m²)"%}</caption> + <tr> + {% for town in dashboard.rescue.surface_by_town %}<th>{{town.town__name}}</th>{% endfor %} + </tr> + <tr> + {% for town in dashboard.rescue.surface_by_town %}<td>{{town.number}}</td>{% endfor%} + </tr> + </table> + </div> + + </div> +</div> +{% endblock %} diff --git a/ishtar_common/templates/dashboard_main.html b/ishtar_common/templates/dashboard_main.html new file mode 100644 index 000000000..e710dbe16 --- /dev/null +++ b/ishtar_common/templates/dashboard_main.html @@ -0,0 +1,82 @@ +{% extends "base.html" %} +{% load i18n %} +{% load range %} +{% block extra_head %} +{{form.media}} +{% endblock %} +{% block content %} +<div class='dashboard'> +{% for lbl, dashboard in items %} + <div> + <h3>{{lbl}}</h3> + <h4>{% trans "Numbers" %}</h4> + <p><strong>{% trans "Total:" %}</strong> {{dashboard.total_number}}</p> + <div class='table'> + <table> + {% for idx, lbl, values in dashboard.values %} + <tr class='idx {% if forloop.counter0|divisibleby:"2" %}even{%else%}odd{%endif%}'> + <th>{{lbl}}</th> + {% for value in values %}<td>{{value}}</td>{% endfor%} + </tr> + {% endfor%} + </table> + </div> + {% if dashboard.years %} + <h4>{% trans "By years" %}</h4> + <ul> + <li><strong>{% trans "Average:" %}</strong> {{dashboard.average}}</li> + <li><strong>{% trans "Variance:" %}</strong> {{dashboard.variance}}</li> + <li><strong>{% trans "Standard deviation:" %}</strong> {{dashboard.standard_deviation}}</li> + <li><strong>{% trans "Median:" %}</strong> {{dashboard.median}}</li> + <li><strong>{% trans "Mode:" %}</strong> {{dashboard.mode}}</li> + </ul> + {% endif %} + {% if dashboard.operation_average %} + <h4>{% trans "By operations" %}</h4> + <ul> + <li><strong>{% trans "Average:" %}</strong> {{dashboard.operation_average}}</li> + <li><strong>{% trans "Variance:" %}</strong> {{dashboard.operation_variance}}</li> + <li><strong>{% trans "Standard deviation:" %}</strong> {{dashboard.operation_standard_deviation}}</li> + <li><strong>{% trans "Median:" %}</strong> {{dashboard.operation_median}}</li> + <li><strong>{% trans "Mode:" %}</strong> {{dashboard.operation_mode}}</li> + </ul> + {% endif %} + <h4>{% trans "Created last" %}</h4> + <div class='table'> + <table> + <tr><th>{{lbl}}</th><th>{% trans "Created" %}</th><th></th></tr> + {% for item in dashboard.lasts %}<tr> + <td class='ref'>{{item}}</td> + <td>{{item.history_date}}</td> + <td>{% if item.get_show_url %}<a href="#" onclick='load_window("{{item.get_show_url}}")'>{%trans "Show"%}</a>{%endif%}</td> + </tr>{% endfor %} + </table> + </div> + <h4>{% trans "Recent changes" %}</h4> + <div class='table'> + <table> + <tr><th>{{lbl}}</th><th>{% trans "Modified" %}</th><th></th></tr> + {% for item in dashboard.recents %}<tr> + <td class='ref'>{{item}}</td> + <td>{{item.history_date}}</td> + <td>{% if item.get_show_url %}<a href="#" onclick='load_window("{{item.get_show_url}}")'>{%trans "Show"%}</a>{%endif%}</td> + </tr>{% endfor %} + </table> + </div> + </div> +{% endfor%} + <div> + <h3>{% trans "Users" %}</h3> + <div class='table'> + <table> + <tr><th>{% trans "User type" %}</th><th>{% trans "Number" %}</th></tr> + {% for user_type in ishtar_users.types %} + <tr> + <td class='string'>{{user_type.person__person_type__label}}</td> + <td>{{user_type.number}}</td> + </tr> + {% endfor%} + </table> + </div> +</div> +{% endblock %} diff --git a/ishtar_common/templates/dashboard_operation.html b/ishtar_common/templates/dashboard_operation.html new file mode 100644 index 000000000..28f1dd9c6 --- /dev/null +++ b/ishtar_common/templates/dashboard_operation.html @@ -0,0 +1,510 @@ +{% extends "base.html" %} +{% load i18n %} +{% load range %} +{% block extra_head %} +{{form.media}} +{% endblock %} +{% block content %} +<div class='dashboard'> + <h2>{% trans "Operations" %}</h2> + <div> + <h3>{% trans "Global informations" %}</h3> + + <div class='table'> + <table> + <caption>{% trans "Total" %}</caption> + <tr> + <th>{% trans "Status" %}</th><th>{% trans "Number" %}</th> + </tr> + {% for lbl, nb in dashboard.total %} + <tr> + <th class='sub'>{{lbl}}</th><td>{{nb}}</td> + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Area by type of operation" %}</caption> + <tr> + <th>{% trans "Status" %}</th><th>{% trans "Area (m²)" %}</th> + </tr> + {% for surface in dashboard.surface_by_type %} + <tr> + <th class='sub'>{{surface.operation_type__label}}</th><td>{{surface.number}}</td> + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "By types" %}</caption> + <tr> + <th>{% trans "State" %}</th>{%for typ in dashboard.types %}<th>{{typ.label}}</th>{% endfor %} + </tr> + {% for lbl, types in dashboard.by_type %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb in types %}<td>{{nb}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "By year" %}</caption> + <tr> + <th>{% trans "State" %}</th>{%for yr in dashboard.years %}<th>{{yr}}</th>{% endfor %} + </tr> + {% for lbl, years in dashboard.by_year %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb in years %}<td>{{nb}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "By realisation year" %}</caption> + <tr> + <th>{% trans "State" %}</th>{%for yr in dashboard.realisation_years %}<th>{{yr.year}}</th>{% endfor %} + </tr> + {% for lbl, years in dashboard.by_realisation_year %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb in years %}<td>{{nb}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Effective operation by type and year" %}</caption> + <tr> + <th>{% trans "Type" %}</th>{%for yr in dashboard.years %}<th>{{yr}}</th>{% endfor %} + </tr> + {% for lbl, years in dashboard.effective %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb in years %}<td>{{nb}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "By realisation month" %}</caption> + <tr> + <th>{% trans "State" %}</th>{%for mt in dashboard.last_months %}<th>{{mt.date|date:"F Y"|capfirst}}</th>{% endfor %} + </tr> + {% for lbl, months in dashboard.by_realisation_month %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb in months %}<td>{{nb}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + </div> + <div> + + <h3>{% trans "Survey informations" %}</h3> + + <div class='table'> + <table> + <caption>{% trans "Total" %}</caption> + <tr> + <th>{% trans "Status" %}</th><th>{% trans "Number" %}</th> + </tr> + {% for lbl, nb in dashboard.survey.total %} + <tr> + <th class='sub'>{{lbl}}</th><td>{{nb}}</td> + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "By year" %}</caption> + <tr> + <th>{% trans "State" %}</th>{%for yr in dashboard.years %}<th>{{yr}}</th>{% endfor %} + </tr> + {% for lbl, years in dashboard.survey.by_year %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb in years %}<td>{{nb}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "By realisation year" %}</caption> + <tr> + <th>{% trans "State" %}</th>{%for yr in dashboard.realisation_years %}<th>{{yr.year}}</th>{% endfor %} + </tr> + {% for lbl, years in dashboard.survey.by_realisation_year %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb in years %}<td>{{nb}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Current year" %}</caption> + <tr> + <th>{% trans "Status" %}</th>{% for lbl in dashboard.filters_label %}<th>{{lbl}}</th>{%endfor%} + </tr> + <tr> + <th class='sub'>{% trans "Area"%}</th>{% for nb in dashboard.survey.area %}<td>{{nb}}</td>{%endfor%} + </tr> + <tr> + <th class='sub'>{% trans "Man-day"%}</th>{% for nb in dashboard.survey.manday %}<td>{{nb}}</td>{%endfor%} + </tr> + <tr> + <th class='sub'>{% trans "Man-day/hectare"%}</th>{% for nb in dashboard.survey.mandayhect %}<td>{{nb}}</td>{%endfor%} + </tr> + </table></div> + + <p><strong>{% trans "Man-day/hectare for effective operations (current year):" %}</strong> {{dashboard.survey.mandayhect_effective}}</p> + + <div class='table'> + <table> + <caption>{% trans "Organizations (current year)" %}</caption> + <tr> + <th> </th><th>{% trans "Area" %}</th><th>{% trans "Man-day" %}</th><th>{% trans "Man-day/hectare" %}</th> + </tr> + {% for org in dashboard.survey.org %} + <tr> + <th class='sub'>{{org.in_charge__attached_to__name}}</th><td>{{org.area}}</td><td>{{org.manday}}</td><td>{{org.mandayhect}}</td> + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Current realisation year" %}</caption> + <tr> + <th>{% trans "Status" %}</th>{% for lbl in dashboard.filters_label %}<th>{{lbl}}</th>{%endfor%} + </tr> + <tr> + <th class='sub'>{% trans "Area"%}</th>{% for nb in dashboard.survey.area_realised %}<td>{{nb}}</td>{%endfor%} + </tr> + <tr> + <th class='sub'>{% trans "Man-day"%}</th>{% for nb in dashboard.survey.manday_realised %}<td>{{nb}}</td>{%endfor%} + </tr> + <tr> + <th class='sub'>{% trans "Man-day/hectare"%}</th>{% for nb in dashboard.survey.mandayhect_realised %}<td>{{nb}}</td>{%endfor%} + </tr> + </table></div> + + <p><strong>{% trans "Man-day/hectare for effective operations (current realisation year):" %}</strong> {{dashboard.survey.mandayhect_real_effective}}</p> + + <div class='table'> + <table> + <caption>{% trans "Organizations (current realisation year)" %}</caption> + <tr> + <th> </th><th>{% trans "Area" %}</th><th>{% trans "Man-day" %}</th><th>{% trans "Man-day/hectare" %}</th> + </tr> + {% for org in dashboard.survey.org_realised %} + <tr> + <th class='sub'>{{org.in_charge__attached_to__name}}</th><td>{{org.area}}</td><td>{{org.manday}}</td><td>{{org.mandayhect}}</td> + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Area by organization by year" %}</caption> + <tr> + <th>{% trans "Organization" %}</th>{% for yr in dashboard.years%}<th>{{yr}}</th>{% endfor %} + </tr> + {% for org, vals in dashboard.survey.org_by_year %} + <tr> + <th class='sub'>{{org}}</th>{% for area, cost in vals %}<td>{{area}}</td>{% endfor %} + </tr> + {% endfor %} + <tr> + <th>{% trans "Mean" %}</th>{% for area in dashboard.survey.org_by_year_area_mean %}<td>{{area}}</td>{% endfor %} + </tr> + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Effective operations areas (m²)" %}</caption> + <tr> + <th> </th>{% for yr in dashboard.years%}<th>{{yr}}</th>{% endfor %} + </tr> + <tr> + <th>{% trans "Sum" %}</th>{% for nb, mean in dashboard.survey.effective %}<td>{{nb}}</td>{% endfor %} + </tr> + <tr> + <th>{% trans "Average" %}</th>{% for nb, avg in dashboard.survey.effective %}<td>{{avg}}</td>{% endfor %} + </tr> + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Man-Days/hectare by Year" %}</caption> + <tr> + <th> </th>{% for yr in dashboard.years%}<th>{{yr}}</th>{% endfor %} + </tr> + <tr> + <th>{% trans "Man-Days/hectare" %}</th>{% for nb, mean in dashboard.survey.mandayshect %}<td>{{nb}}</td>{% endfor %} + </tr> + <tr> + <th>{% trans "Average" %}</th>{% for nb, avg in dashboard.survey.mandayshect %}<td>{{avg}}</td>{% endfor %} + </tr> + </table></div> + + <div class='table'> + <table> + <caption>{% trans "By month" %}</caption> + <tr> + <th>{% trans "State" %}</th>{%for mt in dashboard.last_months %}<th>{{mt.date|date:"F Y"|capfirst}}</th>{% endfor %} + </tr> + {% for lbl, months in dashboard.survey.by_month %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb in months %}<td>{{nb}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "By department" %}</caption> + <tr> + <th>{% trans "Department" %}</th>{%for yr in dashboard.years %}<th>{{yr}}</th>{% endfor %}<th>{% trans "Sum" %}</th> + </tr> + {% for lbl, years in dashboard.survey.by_dpt %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb in years %}<td{%if forloop.last%} class='sub'{%endif%}>{{nb}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Effective operation by department" %}</caption> + <tr> + <th rowspan='2'>{% trans "Department" %}</th>{%for yr in dashboard.years %}<th colspan='2'>{{yr}}</th>{% endfor %}<th colspan='2'>{% trans "Sum" %}</th> + </tr> + <tr> + {%for yr in dashboard.years %}<th>{%trans "Nb."%}</th><th>{%trans "Area"%}</th>{% endfor %}<th>{%trans "Nb."%}</th><th>{%trans "Area"%}</th> + </tr> + {% for lbl, years in dashboard.survey.effective_by_dpt %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb, area, cost, fnap in years %}<td{%if forloop.last%} class='sub'{%endif%}>{{nb}}</td><td{%if forloop.last%} class='sub'{%endif%}>{{area}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Main towns by number" %}</caption> + <tr> + <th>{% trans "Town" %}</th><th>{% trans "Number" %}</th> + </tr> + {% for lbl, nb in dashboard.survey.towns %} + <tr> + <th class='sub'>{{lbl}}</th><td>{{nb}}</td> + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Main towns by surface" %}</caption> + <tr> + <th>{% trans "Town" %}</th><th>{% trans "Total surface (m²)" %}</th> + </tr> + {% for lbl, nb in dashboard.survey.towns_surface %} + <tr> + <th class='sub'>{{lbl}}</th><td>{{nb}}</td> + </tr> + {% endfor %} + </table></div> + + + </div> + <div> + + <h3>{% trans "Excavation informations" %}</h3> + + <div class='table'> + <table> + <caption>{% trans "Total" %}</caption> + <tr> + <th>{% trans "Status" %}</th><th>{% trans "Number" %}</th> + </tr> + {% for lbl, nb in dashboard.excavation.total %} + <tr> + <th class='sub'>{{lbl}}</th><td>{{nb}}</td> + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "By year" %}</caption> + <tr> + <th>{% trans "State" %}</th>{%for yr in dashboard.years %}<th>{{yr}}</th>{% endfor %} + </tr> + {% for lbl, years in dashboard.excavation.by_year %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb in years %}<td>{{nb}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "By realisation year" %}</caption> + <tr> + <th>{% trans "State" %}</th>{%for yr in dashboard.realisation_years %}<th>{{yr.year}}</th>{% endfor %} + </tr> + {% for lbl, years in dashboard.excavation.by_realisation_year %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb in years %}<td>{{nb}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Current realisation year" %}</caption> + <tr> + <th>{% trans "Status" %}</th>{% for lbl in dashboard.filters_label %}<th>{{lbl}}</th>{%endfor%} + </tr> + <tr> + <th class='sub'>{% trans "Area"%}</th>{% for nb in dashboard.excavation.area_realised %}<td>{{nb}}</td>{%endfor%} + </tr> + <tr> + <th class='sub'>{% trans "Man-day"%}</th>{% for nb in dashboard.excavation.manday_realised %}<td>{{nb}}</td>{%endfor%} + </tr> + <tr> + <th class='sub'>{% trans "Man-day/hectare"%}</th>{% for nb in dashboard.excavation.mandayhect_realised %}<td>{{nb}}</td>{%endfor%} + </tr> + </table></div> + + <p><strong>{% trans "Man-day/hectare for effective operations (current realisation year):" %}</strong> {{dashboard.excavation.mandayhect_real_effective}}</p> + + <div class='table'> + <table> + <caption>{% trans "Organizations (current realisation year)" %}</caption> + <tr> + <th> </th><th>{% trans "Area" %}</th><th>{% trans "Man-day" %}</th><th>{% trans "Man-day/hectare" %}</th> + </tr> + {% for org in dashboard.excavation.org_realised %} + <tr> + <th class='sub'>{{org.in_charge__attached_to__name}}</th><td>{{org.area}}</td><td>{{org.manday}}</td><td>{{org.mandayhect}}</td> + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Area by organization by year" %}</caption> + <tr> + <th>{% trans "Organization" %}</th>{% for yr in dashboard.years%}<th>{{yr}}</th>{% endfor %} + </tr> + {% for org, vals in dashboard.excavation.org_by_year %} + <tr> + <th class='sub'>{{org}}</th>{% for area, cost in vals %}<td>{{area}}</td>{% endfor %} + </tr> + {% endfor %} + <tr> + <th>{% trans "Sum" %}</th>{% for area in dashboard.excavation.org_by_year_area_sum %}<td>{{area}}</td>{% endfor %} + </tr> + <tr> + <th>{% trans "Mean" %}</th>{% for area in dashboard.excavation.org_by_year_area_mean %}<td>{{area}}</td>{% endfor %} + </tr> + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Area by organization by realisation year" %}</caption> + <tr> + <th>{% trans "Organization" %}</th>{% for yr in dashboard.years%}<th>{{yr}}</th>{% endfor %} + </tr> + {% for org, vals in dashboard.excavation.org_by_year %} + <tr> + <th class='sub'>{{org}}</th>{% for area, cost in vals %}<td>{{area}}</td>{% endfor %} + </tr> + {% endfor %} + <tr> + <th>{% trans "Sum" %}</th>{% for area in dashboard.excavation.org_by_year_area_sum %}<td>{{area}}</td>{% endfor %} + </tr> + <tr> + <th>{% trans "Mean" %}</th>{% for area in dashboard.excavation.org_by_year_area_mean %}<td>{{area}}</td>{% endfor %} + </tr> + </table></div> + + <div class='table'> + <table> + <caption>{% trans "By month" %}</caption> + <tr> + <th>{% trans "State" %}</th>{%for mt in dashboard.last_months %}<th>{{mt.date|date:"F Y"|capfirst}}</th>{% endfor %} + </tr> + {% for lbl, months in dashboard.excavation.by_month %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb in months %}<td>{{nb}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "By department" %}</caption> + <tr> + <th>{% trans "Department" %}</th>{%for yr in dashboard.years %}<th>{{yr}}</th>{% endfor %}<th>{% trans "Sum" %}</th> + </tr> + {% for lbl, years in dashboard.excavation.by_dpt %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb in years %}<td{%if forloop.last%} class='sub'{%endif%}>{{nb}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Effective operation by department" %}</caption> + <tr> + <th rowspan='2'>{% trans "Department" %}</th>{%for yr in dashboard.years %}<th colspan='3'>{{yr}}</th>{% endfor %}<th colspan='3'>{% trans "Sum" %}</th> + </tr> + <tr> + {%for yr in dashboard.years %}<th>{%trans "Nb."%}</th><th>{%trans "Cost"%}</th><th>{%trans "FNAP cost"%}</th>{% endfor %}<th>{%trans "Nb."%}</th><th>{%trans "Cost"%}</th><th>{%trans "FNAP cost"%}</th> + </tr> + {% for lbl, years in dashboard.excavation.effective_by_dpt %} + <tr> + <th class='sub'>{{lbl}}</th>{%for nb, area, cost, fnap in years %}<td{%if forloop.last%} class='sub'{%endif%}>{{nb}}</td><td{%if forloop.last%} class='sub'{%endif%}>{{cost}}</td><td{%if forloop.last%} class='sub'{%endif%}>{{fnap}}</td>{% endfor %} + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Main towns by number" %}</caption> + <tr> + <th>{% trans "Town" %}</th><th>{% trans "Number" %}</th> + </tr> + {% for lbl, nb in dashboard.excavation.towns %} + <tr> + <th class='sub'>{{lbl}}</th><td>{{nb}}</td> + </tr> + {% endfor %} + </table></div> + + <div class='table'> + <table> + <caption>{% trans "Main towns by cost" %}</caption> + <tr> + <th>{% trans "Town" %}</th><th>{% trans "Cost (€)" %}</th> + </tr> + {% for lbl, nb in dashboard.excavation.towns_cost %} + <tr> + <th class='sub'>{{lbl}}</th><td>{{nb}}</td> + </tr> + {% endfor %} + </table></div> + + + </div> +</div> +{% endblock %} diff --git a/ishtar_common/templates/form_snippet.html b/ishtar_common/templates/form_snippet.html new file mode 100644 index 000000000..2f841e078 --- /dev/null +++ b/ishtar_common/templates/form_snippet.html @@ -0,0 +1,13 @@ +{% load i18n %} + {% if form.non_field_errors %}<tr class='errors'> + <td colspan='3'>{{form.non_field_errors}}</td> + </tr>{%endif%} + {% for field in form %}{% if not field.is_hidden %} + <tr{% if field.field.required %} class='required'{% endif %}> + <th>{{ field.label_tag }}</th> + <td> {{ field.errors }}{{field|safe}}</td>{% if field.help_text %} + <td><a href="#{{field.auto_id}}" class="help_display" title="{% trans "Help"%}">?</a></td> + </tr> + <tr class="help_text" id="{{field.auto_id}}_help"> + <td colspan="3"><div>{{field.help_text}}</div></td> + {%endif%}</tr>{% else %}{{field}}{% endif %}{% endfor %} diff --git a/ishtar_common/templates/index.html b/ishtar_common/templates/index.html new file mode 100644 index 000000000..c4c0b0f2a --- /dev/null +++ b/ishtar_common/templates/index.html @@ -0,0 +1,2 @@ +{% extends "base.html" %} +{% load i18n %} diff --git a/ishtar_common/templates/ishtar/wizard/confirm_wizard.html b/ishtar_common/templates/ishtar/wizard/confirm_wizard.html new file mode 100644 index 000000000..bd80e3967 --- /dev/null +++ b/ishtar_common/templates/ishtar/wizard/confirm_wizard.html @@ -0,0 +1,34 @@ +{% extends "base.html" %} +{% load i18n %} +{% load range %} +{% block content %} +<form action="." method="post">{% csrf_token %} +<ul id='form_path'> +{% for step in previous_steps %} + <li>» <button name="form_prev_step" value="{{forloop.counter0}}">{{step.form_label}}</button></li> +{% endfor %} + <li class='current'>» <a href='#'>{{current_step.form_label}}</a></li> +</ul> +<div class='form'> + <p>{%if confirm_msg %}{{confirm_msg|safe}}{%else%}{% trans "You have entered the following informations:" %}{%endif%}</p> + {% for form_label, form_data in datas %} + <table class='confirm'> + <caption>{{form_label}}</caption> + {% for label, data, cls in form_data %} + <tr{%if cls%} class='{{cls}}'{%endif%}><th>{{label}}</th><td>{{data}}</td></tr> + {% endfor %} + </table> + {% endfor %} +{{wizard.management_form}} + {%if not wizard.form.is_hidden %} + <table> + {{ wizard.form.as_table }} + </table> + {%endif%} + <p>{%if confirm_end_msg %}{{confirm_end_msg|safe}}{%else%}{% trans "Would you like to save them?" %}{%endif%}</p> + <input type="hidden" name="{{ step_field }}" value="{{ step0 }}" /> + {{ previous_fields|safe }} + <input type="submit" value="{% trans "Validate" %}"/> +</div> +</form> +{% endblock %} diff --git a/ishtar_common/templates/ishtar/wizard/default_wizard.html b/ishtar_common/templates/ishtar/wizard/default_wizard.html new file mode 100644 index 000000000..1996f4e46 --- /dev/null +++ b/ishtar_common/templates/ishtar/wizard/default_wizard.html @@ -0,0 +1,44 @@ +{% extends "base.html" %} +{% load i18n %} +{% load range %} +{% load table_form %} +{% block extra_head %} +{{form.media}} +{% endblock %} +{% block content %} +<form action="." method="post" name='wizard'>{% csrf_token %} +<ul id='form_path'> +{% for step in previous_steps %} + <li>» <button name="form_prev_step" value="{{forloop.counter0}}">{{step.form_label}}</button></li> +{% endfor %} + <li class='current'>» <a href='#'>{{current_step.form_label}}</a></li> +{% for step in next_steps %} + <li>» <button name="form_prev_step" value="{{forloop.counter|add:previous_step_counter}}">{{step.form_label}}</button></li> +{% endfor %} +</ul> +<div class='form'> +{% if reminder %}<div class='reminder'>{{ reminder }}</div>{%endif%} +{{ wizard.form.media }} +{{ wizard.management_form }} +{% if wizard.form.forms %} + {{ wizard.form.management_form }} +<div class='top_button'><input type="submit" id="submit_form" value="{% trans "Validate" %}"/></div> +<table class='formset'> + {%if wizard.form.non_form_errors%}<tr class='error'><th colspan='2'>{{wizard.form.non_form_errors}}</th></tr>{%endif%} + {% for formsetform in wizard.form.forms %} + {% table_form formsetform %} + {% endfor %} + <tr class='modify'><td colspan="2"><button name="formset_modify" value="{{form_step}}">{% trans "Add/Modify" %}</button></td></tr></li> +</table> +{% else %} +<table> +{% table_form wizard.form %} +</table> +{% endif %} +<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" /> +{{ previous_fields|safe }} +<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> +</form> +{% endblock %} diff --git a/ishtar_common/templates/registration/activate.html b/ishtar_common/templates/registration/activate.html new file mode 100644 index 000000000..0dcbccc00 --- /dev/null +++ b/ishtar_common/templates/registration/activate.html @@ -0,0 +1,18 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} +<div class='info'> +{% if account %} + +<p>{% trans "Account successfully activated" %}</p> + +<p><a href="{% url auth_login %}">{% trans "Log in" %}</a></p> + +{% else %} + +<p>{% trans "Account activation failed" %}</p> + +{% endif %} +</div> +{% endblock %} diff --git a/ishtar_common/templates/registration/activation_email.txt b/ishtar_common/templates/registration/activation_email.txt new file mode 100644 index 000000000..b30035969 --- /dev/null +++ b/ishtar_common/templates/registration/activation_email.txt @@ -0,0 +1,6 @@ +{% load i18n %} +{% trans "Activate account at" %} {{ site.name }}: + +http://{{ site.domain }}{% url registration_activate activation_key %} + +{% blocktrans %}Link is valid for {{ expiration_days }} days.{% endblocktrans %} diff --git a/ishtar_common/templates/registration/activation_email_subject.txt b/ishtar_common/templates/registration/activation_email_subject.txt new file mode 100644 index 000000000..24f477cbb --- /dev/null +++ b/ishtar_common/templates/registration/activation_email_subject.txt @@ -0,0 +1 @@ +{% load i18n %}{% trans "Account activation on" %} {{ site.name }} diff --git a/ishtar_common/templates/registration/login.html b/ishtar_common/templates/registration/login.html new file mode 100644 index 000000000..ada4f6aa9 --- /dev/null +++ b/ishtar_common/templates/registration/login.html @@ -0,0 +1,19 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} +<div class='form'> +<form method="post" action=".">{% csrf_token %} +<table id='login'> + <caption>{%trans "Log in"%}</caption> +{{ form.as_table }} + <tr class='submit'><td colspan='2'><input type="submit" value="{% trans 'Log in' %}" /></td></tr> + <input type="hidden" name="next" value="{{ next }}" /> +</table> +</form> +</div> +<div class='info'> +<p>{% trans "Forgot password?" %} <a href="{% url auth_password_reset %}">{% trans "Reset it" %}</a></p> +<p>{% trans "Not member?" %} <a href="{% url registration_register %}">{% trans "Register" %}</a></p> +</div> +{% endblock %} diff --git a/ishtar_common/templates/registration/logout.html b/ishtar_common/templates/registration/logout.html new file mode 100644 index 000000000..029a0c25b --- /dev/null +++ b/ishtar_common/templates/registration/logout.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} +<div class='info'> +<p>{% trans "Logged out" %}</p> +</div> +{% endblock %} diff --git a/ishtar_common/templates/registration/password_change_done.html b/ishtar_common/templates/registration/password_change_done.html new file mode 100644 index 000000000..9d442360c --- /dev/null +++ b/ishtar_common/templates/registration/password_change_done.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} +<div class='info'> +<p>{% trans "Password changed" %}</p> +</div> +{% endblock %} diff --git a/ishtar_common/templates/registration/password_change_form.html b/ishtar_common/templates/registration/password_change_form.html new file mode 100644 index 000000000..84d915eaa --- /dev/null +++ b/ishtar_common/templates/registration/password_change_form.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} +<div class='form'> +<form method="post" action=".">{% csrf_token %} + <table> + {{ form.as_table }} + + <tr><td colspan='2'><input type="submit" value="{% trans 'Submit' %}" /></td></tr> + </table> +</form> +</p> +{% endblock %} diff --git a/ishtar_common/templates/registration/password_reset_complete.html b/ishtar_common/templates/registration/password_reset_complete.html new file mode 100644 index 000000000..dfa3ce682 --- /dev/null +++ b/ishtar_common/templates/registration/password_reset_complete.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} +<div class='info'> +<p>{% trans "Password reset successfully" %}</p> + +<p><a href="{% url auth_login %}">{% trans "Log in" %}</a></p> +</div> +{% endblock %} diff --git a/ishtar_common/templates/registration/password_reset_confirm.html b/ishtar_common/templates/registration/password_reset_confirm.html new file mode 100644 index 000000000..b0e2cc142 --- /dev/null +++ b/ishtar_common/templates/registration/password_reset_confirm.html @@ -0,0 +1,21 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} + +{% if validlink %} +<div class='form'> +<form method="post" action=".">{% csrf_token %} + <table> + {{ form.as_table }} + <tr><td colspan='2'><input type="submit" value="{% trans 'Submit' %}" /></td></tr> + </table> +</form> +</div> +{% else %} +<div class='info'> +<p>{% trans "Password reset failed" %}</p> +</div> +{% endif %} + +{% endblock %} diff --git a/ishtar_common/templates/registration/password_reset_done.html b/ishtar_common/templates/registration/password_reset_done.html new file mode 100644 index 000000000..cc7d9b40e --- /dev/null +++ b/ishtar_common/templates/registration/password_reset_done.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} +<div class='info'> +<p>{% trans "Email with password reset instructions has been sent." %}</p> +</div> +{% endblock %} diff --git a/ishtar_common/templates/registration/password_reset_email.html b/ishtar_common/templates/registration/password_reset_email.html new file mode 100644 index 000000000..a55c86958 --- /dev/null +++ b/ishtar_common/templates/registration/password_reset_email.html @@ -0,0 +1,5 @@ +{% load i18n %} +{% blocktrans %}Reset password at {{ site_name }}{% endblocktrans %}: +{% block reset_link %} +{{ protocol }}://{{ domain }}{% url auth_password_reset_confirm uidb36=uid, token=token %} +{% endblock %} diff --git a/ishtar_common/templates/registration/password_reset_form.html b/ishtar_common/templates/registration/password_reset_form.html new file mode 100644 index 000000000..d6fad7a0a --- /dev/null +++ b/ishtar_common/templates/registration/password_reset_form.html @@ -0,0 +1,15 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} +<div class='form'> +<form method="post" action=".">{% csrf_token %} + <caption>{% trans "Reset password" %}</caption> + <table> + {{ form.as_table }} + + <tr><td colspan='2'><input type="submit" value="{% trans 'Submit' %}" /></td></tr> + </table> +</form> +</div> +{% endblock %} diff --git a/ishtar_common/templates/registration/registration_complete.html b/ishtar_common/templates/registration/registration_complete.html new file mode 100644 index 000000000..e9f487444 --- /dev/null +++ b/ishtar_common/templates/registration/registration_complete.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} +<div class='info'> +<p>{% trans "You are now registered. Activation email sent." %}</p> +</div> +{% endblock %} diff --git a/ishtar_common/templates/registration/registration_form.html b/ishtar_common/templates/registration/registration_form.html new file mode 100644 index 000000000..b15f0e74b --- /dev/null +++ b/ishtar_common/templates/registration/registration_form.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} +{% load i18n %} + +{% block content %} +<div class='form'> +<form method="post" action=".">{% csrf_token %} + <table> + <caption>{% trans "Register" %}</caption> + {{ form.as_table }} + <tr><td colspan='2'><input type="submit" value="{% trans 'Submit' %}" /></td></tr> + </table> +</form> +</div> +{% endblock %} diff --git a/ishtar_common/templates/search.html b/ishtar_common/templates/search.html new file mode 100644 index 000000000..1b5829820 --- /dev/null +++ b/ishtar_common/templates/search.html @@ -0,0 +1,28 @@ +{% extends "base.html" %} +{% load i18n %} +{% load range %} +{% block extra_head %} +{{form.media}} +{% endblock %} +{% block content %} +<ul id='form_path'> + <li class='current'>» <a href='#'>{{form.form_label}}</a></li> +</ul> +<div class='form'> +{% if form.forms %} +<div class='top_button'><input type="submit" id="submit_form" value="{% trans "Validate" %}"/></div> +<table class='formset'> + {%if form.non_form_errors%}<tr class='error'><th colspan='2'>{{form.non_form_errors}}</th></tr>{%endif%} + {{ form.management_form }} + {% for formsetform in form.forms %} + {{ formsetform.as_table }} + {% endfor %} + <tr class='modify'><td colspan="2"><button name="formset_modify" value="{{form_step}}">{% trans "Add/Modify" %}</button></td></tr></li> +</table> +{% else %} +<table> + {{ form.as_table }} +</table> +{% endif %} +</div> +{% endblock %} diff --git a/ishtar_common/templates/sheet.html b/ishtar_common/templates/sheet.html new file mode 100644 index 000000000..5608a684f --- /dev/null +++ b/ishtar_common/templates/sheet.html @@ -0,0 +1,30 @@ +{% load i18n %} +{% block main_head %} +<!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 %}Ishtar{% if APP_NAME %} - {{APP_NAME}}{%endif%}{% endblock %} + </title> + {% block css_head %} + <link rel="stylesheet" href="{{MEDIA_URL}}/media/style.css" /> + {% endblock %} +</head> +<body> +{% endblock %} +<div class="sheet" id='{{window_id}}'> +{% block head_sheet %} +<script type="text/javascript">var last_window='{{window_id}}';</script> +<div class="head"> +<a href='#' onclick='$("#{{window_id}}").hide("slow")'>{% trans "Close" %}</a> - +<a href='#' onclick='closeAllWindows();'> +{% trans "Close all windows" %} +</a></div>{% endblock %} +<div class="body"> +{% block content %}{% endblock %} +</div> +</div> +{%block main_foot%} +</body> +</html> +{%endblock%} diff --git a/ishtar_common/templates/sheet_contextrecord.html b/ishtar_common/templates/sheet_contextrecord.html new file mode 100644 index 000000000..c2b94bafe --- /dev/null +++ b/ishtar_common/templates/sheet_contextrecord.html @@ -0,0 +1,135 @@ +{% extends "sheet.html" %} +{% load i18n %} +{% block content %} +<div class='tool'>{%trans "Export as:"%} <a href='{% url show-file item.pk "odt" %}'>{%trans "OpenOffice.org file"%}</a>, <a href='{% url show-file item.pk "pdf" %}'>{%trans "PDF file"%}</a></div> + +<h3>{% trans "Context Record"%}</h3> + +{% if item.operation.code_patriarche %} +<p><label>{%trans "Complete ID:"%}</label> +{% else %} +<p class='alert'><label>{%trans "Patriarche OA code not yet recorded!"%}</label></p> +<p><label>{%trans "Temporary ID:"%}</label> +{%endif%} +<span class='value'>{{item.full_label}}</span></p> +{%if item.unit %} +<p><label>{% trans "Type:" %}</label> <span class='value'>{{ item.unit }}</span></p> +{%endif%} +<p><label>{% trans "Chronology:" %}</label> <span class='value'>{{ item.datings.all|join:", " }}</span></p> +<p><label>{% trans "Place:" %}</label> <span class='value'>{{ item.parcel.town }}</span></p> +<p><label>{% trans "Parcel:" %}</label> <span class='value'>{{ item.parcel.short_label }}</span></p> + +{% if item.description or item.lenght or item.width or item.depth %} +<h3>{% trans "Description"%}</h3> + +<p><label>{% trans "Description:" %}</label> <span class='value'>{{ item.description }}</span></p> +{% if item.lenght %}<p><label>{% trans "Length (cm):" %}</label> <span class='value'>{{ item.length }}</span></p>{%endif%} +{% if item.width %}<p><label>{% trans "Width (cm):" %}</label> <span class='value'>{{ item.width }}</span></p>{%endif%} +{% if item.depth %}<p><label>{% trans "Depth (cm):" %}</label> <span class='value'>{{ item.depth }}</span></p>{%endif%} +{% endif %} + +{% if item.activity or item.identification or item.interpretation %} +<h3>{% trans "Interpretation"%}</h3> + +{% if item.activity %}<p><label>{% trans "Activity:" %}</label> <span class='value'>{{ item.activity }}</span></p>{%endif%} +{% if item.identification %}<p><label>{% trans "Identification:" %}</label> <span class='value'>{{ item.identification }}</span></p>{%endif%} +{% if item.interpretation %}<p><label>{% trans "Interpretation:" %}</label> <span class='value'>{{ item.interpretation }}</span></p>{%endif%} +{% endif %} + +{% if item.taq or item.taq_estimated or item.tpq or item.tpq_estimated %} +<h3>{% trans "Datations"%}</h3> +{% if item.taq %}<p><label>{% trans "TAQ:" %}</label> <span class='value'>{{ item.taq }}</span></p>{%endif%} +{% if item.taq_estimated %}<p><label>{% trans "TAQ estimated:" %}</label> <span class='value'>{{ item.taq_estimated }}</span></p>{%endif%} +{% if item.tpq %}<p><label>{% trans "TPQ:" %}</label> <span class='value'>{{ item.tpq }}</span></p>{%endif%} +{% if item.tpq_estimated %}<p><label>{% trans "TPQ estimated:" %}</label> <span class='value'>{{ item.tpq_estimated }}</span></p>{%endif%} +{%endif%} + +{% if item.operation %} +<h3>{% trans "Operation resume"%}</h3> +<p><label>{%trans "Year:"%}</label> <span class='value'>{{ item.operation.year }}</span></p> +<p><label>{%trans "Numerical reference:"%}</label> <span class='value'>{{ item.operation.operation_code }}</span></p> +{% if item.operation.code_patriarche %} +<p><label>{%trans "Patriarche OA code:"%}</label> +<span class='value'>{{ item.operation.code_patriarche }}</span></p> +{% else %}<p class='alert'><label>{%trans "Patriarche OA code not yet recorded!"%}</label></p> +{%endif%} +{#<p><label>{%trans "Operation's name:"%}</label><span class='value'>{{ item.operation.internal_reference }}</span></p>#} +<p><label>{%trans "Head scientist:"%}</label> +<span class='value'>{{ item.operation.in_charge.full_label }}</span></p> +<p><label>{%trans "State:"%}</label> +{% if item.operation.is_active %} +<span class='value'>{%trans "Active file"%}</span></p> +{% else %} +<span class='value'>{%trans "Closed operation"%}</span></p> +<p><label>{%trans "Closing date:"%}</label> <span class='value'>{{ item.operation.closing.date }} +<strong>{%trans "by" %}</strong> {{ item.operation.closing.user }}</span></p> +{% endif %} +<p><label>{%trans "Type:"%}</label> <span class='value'>{{ item.operation.operation_type }}</span></p> +<p><label>{%trans "Remains:"%}</label> <span class='value'>{{ item.operation.remains.all|join:", " }}</span></p> +<p><label>{%trans "Periods:"%}</label> <span class='value'>{{ item.operation.periods.all|join:", " }}</span></p> +{% if item.operation.comment %}<p><label>{%trans "Comment:"%}</label> <span class='value'>{{ item.operation.comment }}</span></p>{%endif%} +<h3>{% trans "Localisation"%}</h3> +<p><label>{%trans "Towns:"%}</label> <span class='value'>{{ item.operation.towns.all|join:", " }}</span></p> +<p><label>{%trans "Related operation:"%}</label> +<span class='value'><a href="#" onclick='load_window("{% url show-operation item.operation.pk ''%}");'>{{ item.operation }}</a></span></p> +{# TODO: Displayed as Year/index/Commune/Common_name This should be a link to the file sheet of the related operation #} +{% else %}<p class='alert'><label>{%trans "No operation linked to this context unit!"%}</label></p> +{% endif %} + +<table> + <caption>{%trans "Documents"%}</caption> + <tr> + <th>{% trans "Title" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "Authors" %}</th> + {#<th>{% trans "Localisation" %}</th>#} + </tr> + {% for doc in item.source.all %} + <tr> + <td class='string'>{{ doc.title }}</td> + <td class='string'>{{doc.source_type}}</td> + <td class='string'>{{ doc.authors.all|join:", " }}</td> + {#<td>{{ doc.localisation }}</td>#} + </tr> + {% empty %} + <tr><td colspan="4" class='no_items'>{% trans "No document associated to this context record" %}</td></tr> + {% endfor %} +</table> + +<table> + <caption>{%trans "Finds"%}</caption> + <tr> + <th>{% trans "Find" %}</th> + <th>{% trans "Material type" %}</th> + <th>{% trans "Context record" %}</th> + <th>{% trans "Periods" %}</th> + <th>{% trans "Description" %}</th> + <th>{% trans "Weight" %}</th> + <th>{% trans "Numbers" %}</th> + <th>{% trans "Parcel" %}</th> + <th class='link'> </th> + </tr> + {% for find in item.base_items.all %} + <tr> + <td>{{ find.full_label }}</td> +{# Displayed as (Patriarche operation code)-(Record unit label)-(Finds label). #} +{# or displayed as (Year)-(index)-(Record unit label)-(Finds label). #} + <td>{{ find.material_type_label }}</td> +{# Displayed as (Patriarche operation code)-(Record unit label)-(material code)-(Finds label indexed by material type). #} +{# or displayed as (Year)-(index)-(Record unit label)-(material code)-(Finds label indexed by material type) #} + + <td class='string'>{{find.context_record}}</td> + <td>{{ find.get_last_item.dating}}</td>{# TODO .all|join:", " ? #} + <td>{{ find.get_last_item.description }}</td> + <td>{{ find.get_last_item.weight }}</td> + <td>{{ find.get_last_item.item_number }}</td> + <td>{{ item.context_record.parcel.short_label }}</td> + <td class='link'><a href="#">{% trans "Details" %}</a></td> + {#<a href="#" onclick='load_window("{% url show-find find.pk%}");'>{%trans "Details"%}</a></td>#} + </tr> + {% empty %} + <tr><td colspan="9" class='no_items'>{% trans "No find associated to this context record" %}</td></tr> + {% endfor %} +</table> + +{% endblock %} diff --git a/ishtar_common/templates/sheet_contextrecord_window.html b/ishtar_common/templates/sheet_contextrecord_window.html new file mode 100644 index 000000000..7ff65d1e7 --- /dev/null +++ b/ishtar_common/templates/sheet_contextrecord_window.html @@ -0,0 +1,3 @@ +{% extends "sheet_contextrecord.html" %} +{% block main_head %}{%endblock%} +{% block main_foot %}{%endblock%} diff --git a/ishtar_common/templates/sheet_file.html b/ishtar_common/templates/sheet_file.html new file mode 100644 index 000000000..88ef1b3a2 --- /dev/null +++ b/ishtar_common/templates/sheet_file.html @@ -0,0 +1,132 @@ +{% extends "sheet.html" %} +{% load i18n %} +{% block content %} +{% if previous or next %} +<div class='tool'> +{%if previous%} +<a href="#" onclick='load_window("{% url show-historized-file item.pk previous|date:"c"%}");$("#{{window_id}}").hide();return false;'>{%trans "Previous version"%} ({{previous}})</a> +{% endif %} +{% if previous and next %} - {% endif %} +{%if next%} +<a href="#" onclick='if(confirm("{%trans "Are you sure to rollback to this version?"%}")){load_url("{% url revert-file item.pk item.history_date|date:"c"%}");closeAllWindows();load_window("{% url show-file item.pk None %}");}'>Rollback</a> - +<a href="#" onclick='load_window("{% url show-historized-file item.pk next|date:"c" %}");$("#{{window_id}}").hide();return false;'>{%trans "Next version"%} ({{next}})</a> +{% endif %} +</div> +{% endif %} +<div class='tool'>{%trans "Export as:"%} <a href='{% url show-file item.pk "odt" %}'>{%trans "OpenOffice.org file"%}</a>, <a href='{% url show-file item.pk "pdf" %}'>{%trans "PDF file"%}</a></div> +<h3>{% trans "General"%}</h3> +<p><label>{%trans "Year:"%}</label> <span class='value'>{{ item.year }}</span></p> +<p><label>{%trans "Numerical reference:"%}</label> <span class='value'>{{ item.numeric_reference }}</span></p> + +<p><label>{%trans "File's name:"%}</label> <span class='value'>{{ item.internal_reference }}</span></p> + +<p><label>{%trans "Edition date:"%}</label> <span class='value'>{{ item.history_date }}</span></p> <!-- date = now --> +{% if item.reception_date %}<p><label>{%trans "Reception date:"%}</label> <span class='value'>{{ item.reception_date }}</span></p>{% endif %} +<p><label>{%trans "Creation date:"%}</label> <span class='value'>{{ item.creation_date }}</span></p> +{% comment %} +{% if item.deadline_date and not item.acts %} + <p><label>{%trans "Deadline:"%}</label> <span class='value'>{% item.deadline_date %}</span></p> <!-- calculated deadline for some preventive files , see saisine_type, not displayed if an act as been send --> +{% endif %} +{% endcomment %} + +<p><label>{%trans "In charge:"%}</label> <span class='value'>{{ item.in_charge.full_label }}</span></p> +<p><label>{%trans "State:"%}</label> <span class='value'>{% if item.is_active %}{%trans "Active file"%}</span></p> +{% else %}{%trans "Closed file"%}</span></p> +<p><label>{%trans "Closing date:"%}</label> <span class='value'>{{ item.closing.date }} <strong>{%trans "by" %}</strong> {{ item.closing.user }}</span></p> +{% endif %} + +<p><label>{%trans "Type:"%}</label> <span class='value'>{{ item.file_type }}</span></p> + +{% if item.related_file %}<p><label>{%trans "Related file:"%}</label> <span class='value'><a href='#' onclick='load_window("{% url show-file item.related_file.pk ''%}")'>{{ item.related_file }}</a></span></p>{% endif %} <!-- Displayed as Year/index/Commune/Common_name This should be a link to the file sheet of the related file --> +{% if item.comment %}<p><label>{%trans "Comment:"%}</label> <span class='value'>{{ item.comment }}</span></p>{%endif%} + +<h3>{% trans "Localisation"%}</h3> +<p><label>{%trans "Towns:"%}</label> <span class='value'>{{ item.towns.all|join:", " }}</span></p> + +<p><label>{%trans "Main address:"%}</label> <span class='value'>{{ item.address }}</span></p> +{% if item.address_complement %}<p><label>{%trans "Complement:"%}</label> <span class='value'>{{ item.address_complement }}</span></p>{%endif%} +{% if item.postal_code %}<p><label>{%trans "Postal code:"%}</label> <span class='value'>{{ item.postal_code }}</span></p>{%endif%} + +<p><label>{%trans "Surface:"%}</label>{% if item.total_surface %} <span class='value'>{{ item.total_surface }} m<sup>2</sup> ({{ item.total_surface_ha }} ha)</span>{%endif%}</p> + + + +{% if item.is_preventive %} +<h3>{% trans "Preventive archaelogical file"%}</h3> +<p><label>{%trans "Planed surface:"%}</label> <span class='value'>{{ item.total_developed_surface }} m<sup>2</sup> ({{ item.total_developed_surface_ha }} ha)</span></p> +<p><label>{%trans "Saisine type:"%}</label> <span class='value'>{{ item.saisine_type }}</span></p> +{% if item.town_planning_service %}<p><label>{%trans "Town planning service:"%}</label> <span class='value'>{{ item.town_planning_service }}</span></p>{% endif %} +{% if item.permit_type %}<p><label>{%trans "Permit type:"%}</label> <span class='value'>{{ item.permit_type }}</span></p>{% endif %} +{% if item.permit_reference %}<p><label>{%trans "Permit reference:"%}</label> <span class='value'>{{ item.permit_reference }}</span></p>{% endif %} +{% if item.general_contractor.attached_to %}<p><label>{%trans "General contractor organisation:"%}</label> <span class='value'>{{ item.general_contractor.attached_to }}</span></p>{% endif %} <!-- Contractor's organisation displayed as concat of Name/Adress/postal_code/city --> +{% if item.general_contractor %}<p><label>{%trans "General contractor:"%}</label> <span class='value'>{{ item.general_contractor.full_label }}</span></p>{% endif %} +{% endif %} + +<table> + <caption>{%trans "Admninistrative acts"%}</caption> + <tr> + <th>{% trans "Year" %}</th> + <th>{% trans "Reference" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "Date" %}</th> + </tr> + {% for act in item.administrative_act.all %} + <tr> + <td>{{act.signature_date.year}}</td> + <td>{{act.ref_sra}}</td> + <td class='string'>{{act.act_type}}</td> + <td>{{act.signature_date}}</td> + </tr> + {% empty %} + <tr><td colspan="4" class='no_items'>{% trans "No administrative act associated to this archaelogical file" %}</td></tr> + {% endfor %} +</table> + +<table> + <caption>{%trans "Associated operations"%}</caption> + <tr> + <th>{% trans "Year" %}</th> + <th>{% trans "Reference" %}</th> + <th>Code Patriarche</th> + <th>{% trans "Type" %}</th> + <th>{% trans "In charge" %}</th> + <th>{% trans "Start date" %}</th> + <th>{% trans "Excavation end date" %}</th> + <th class='link'> </th> + </tr> + {% for operation in item.operations.all %} + <tr> + <td>{{operation.year}}</td> + <td>{{operation.operation_code}}</td> + <td>{{operation.code_patriarche|default:""}}</td> + <td class='string'>{{operation.operation_type}}</td> + <td class='string'>{{operation.in_charge|default:""}}</td> + <td>{{operation.start_date|default:""}}</td> + <td>{{operation.excavation_end_date|default:""}}</td> + <td class='link'><a href="#" onclick='load_window("{%url show-operation operation.pk ''%}")'>{% trans "Details" %}</a></td> + </tr> + {% empty %} + <tr><td colspan="8" class='no_items'>{% trans "No operation associated to this archaelogical file" %}</td></tr> + {% endfor %} +</table> + +<table> + <caption>{%trans "Admninistrative acts linked to associated operations"%}</caption> + <tr> + <th>{% trans "Year" %}</th> + <th>{% trans "Reference" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "Date" %}</th> + </tr> + {% for act in item.operation_acts %} + <tr> + <td>{{act.signature_date.year}}</td> + <td>{{act.ref_sra}}</td> + <td class='string'>{{act.act_type}}</td> + <td>{{act.signature_date}}</td> + </tr> + {% empty %} + <tr><td colspan="4" class='no_items'>{% trans "No administrative act linked to operations" %}</td></tr> + {% endfor %} +</table> +{% endblock %} diff --git a/ishtar_common/templates/sheet_file_pdf.html b/ishtar_common/templates/sheet_file_pdf.html new file mode 100644 index 000000000..3c77c75f8 --- /dev/null +++ b/ishtar_common/templates/sheet_file_pdf.html @@ -0,0 +1,18 @@ +{% extends "sheet_file.html" %} +{% block css_head %} +<link rel="stylesheet" href="{{MEDIA_URL}}/media/style_basic.css" /> +{% endblock %} +{% block main_head %} +{{ block.super }} +<div id="pdfheader"> +Ishtar – {{APP_NAME}} – {{item}} +</div> +{% endblock %} +{%block head_sheet%}{%endblock%} +{%block main_foot%} +<div id="pdffooter"> +– <pdf:pagenumber/> – +</div> +</body> +</html> +{%endblock%} diff --git a/ishtar_common/templates/sheet_file_window.html b/ishtar_common/templates/sheet_file_window.html new file mode 100644 index 000000000..e9debdd0d --- /dev/null +++ b/ishtar_common/templates/sheet_file_window.html @@ -0,0 +1,3 @@ +{% extends "sheet_file.html" %} +{% block main_head %}{%endblock%} +{% block main_foot %}{%endblock%} diff --git a/ishtar_common/templates/sheet_ope.html b/ishtar_common/templates/sheet_ope.html new file mode 100644 index 000000000..dbe3297b3 --- /dev/null +++ b/ishtar_common/templates/sheet_ope.html @@ -0,0 +1,146 @@ +{% extends "sheet.html" %} +{% load i18n %} +{% block content %} +<div class='tool'>{%trans "Export as:"%} <a href='{% url show-file item.pk "odt" %}'>{%trans "OpenOffice.org file"%}</a>, <a href='{% url show-file item.pk "pdf" %}'>{%trans "PDF file"%}</a></div> +<h3>{% trans "General"%}</h3> +<p><label>{%trans "Year:"%}</label> <span class='value'>{{ item.year }}</span></p> +<p><label>{%trans "Numerical reference:"%}</label> <span class='value'>{{ item.numeric_reference }}</span></p> + +{% if item.patriarche_code %}<p><label>{%trans "Patriarche OA code:"%}</label> <span class='value'>{{ item.patriarche_code }}</span></p>{%endif%} +{% if item.patriarche_code_not_recorded %}<p><label>{%trans "Patriarche OA code not yet recorded !"%}</label></p>{%endif%} + +<p><label>{%trans "Operation's name:"%}</label> <span class='value'>{{ item.internal_reference }}</span></p> + +<p><label>{%trans "Edition date:"%}</label> <span class='value'>{{ item.history.all.0.history_date }}</span></p> <!-- date = now --> + +<p><label>{%trans "Begining date:"%}</label> <span class='value'>{{ item.begin_date }}</span></p> +<p><label>{%trans "Field work end date:"%}</label> <span class='value'>{{ item.end_date }}</span></p> + +<p><label>{%trans "Head scientist:"%}</label> <span class='value'>{{ item.head_scientist.full_label }}</span></p> +<p><label>{%trans "State:"%}</label> <span class='value'>{% if item.is_active %}{%trans "Active file"%}</span></p> +{% else %}{%trans "Closed operation"%}</span></p> +<p><label>{%trans "Closing date:"%}</label> <span class='value'>{{ item.closing.date }} <strong>{%trans "by" %}</strong> {{ item.closing.user }}</span></p> +{% endif %} +<p><label>{%trans "Type:"%}</label> <span class='value'>{{ item.operation_type }}</span></p> +<p><label>{%trans "Surface:"%}</label> <span class='value'>{{ item.total_surface }} m<sup>2</sup> ({{ item.total_surface_ha }} ha)</span></p> +<p><label>{%trans "Cost:"%}</label> <span class='value'>{{ item.cost }} Euros, ({{ item.cost_by_m2 }} Euros/m<sup>2</sup>)</span></p> +<p><label>{%trans "Duration:"%}</label> <span class='value'>{{ item.duration }} {%trans "Day"%}s</span></p> + +<p><label>{%trans "Remains:"%}</label> <span class='value'>{{ item.remains.all|join:", " }}</span></p> +<p><label>{%trans "Periods:"%}</label> <span class='value'>{{ item.periods.all|join:", " }}</span></p> + +{% if item.related_file %} +<p><label>{%trans "Related file:"%}</label> <span class='value'><a href='{% url show-file item.related_file.pk ''%}'>{{ item.related_file }}</a></span></p><!-- Displayed as Year/index/Commune/Common_name This should be a link to the file sheet of the related file --> +{% if item.related_file.is_preventive %} +{% if item.operator_reference_code %}<p><label>{%trans "Operator's reference code:"%}</label> <span class='value'>{{ item.operator_reference_code }}</span></p>{% endif %} +{% if item.related_file.town_planning_service %}<p><label>{%trans "Town planning service:"%}</label> <span class='value'>{{ item.related_file.town_planning_service }}</span></p>{% endif %} +{% if item.related_file.permit_type %}<p><label>{%trans "Permit type:"%}</label> <span class='value'>{{ item.related_file.permit_type }}</span></p>{% endif %} +{% if item.related_file.permit_reference %}<p><label>{%trans "Permit reference:"%}</label> <span class='value'>{{ item.related_file.permit_reference }}</span></p>{% endif %} +{% if item.related_file.general_contractor.attached_to %}<p><label>{%trans "General contractor organisation:"%}</label> <span class='value'>{{ item.related_file.general_contractor.attached_to }}</span></p>{% endif %} <!-- Contractor's organisation displayed as concat of Name/Adress/postal_code/city --> +{% if item.related_file.general_contractor %}<p><label>{%trans "General contractor:"%}</label> <span class='value'>{{ item.related_file.general_contractor.full_label }}</span></p>{% endif %} +{% endif %} +{% endif %} + +{% if item.comment %}<p><label>{%trans "Comment:"%}</label> <span class='value'>{{ item.comment }}</span></p>{%endif%} + +<h3>{% trans "Localisation"%}</h3> +<p><label>{%trans "Towns:"%}</label> <span class='value'>{{ item.towns.all|join:", " }}</span></p> + +<p><label>{%trans "Main address:"%}</label> <span class='value'>{{ item.address }}</span></p> +{% if item.address_complement %}<p><label>{%trans "Complement:"%}</label> <span class='value'>{{ item.address_complement }}</span></p>{%endif%} +{% if item.postal_code %}<p><label>{%trans "Postal code:"%}</label> <span class='value'>{{ item.postal_code }}</span></p>{%endif%} + +<p><label>{%trans "Lambert X:"%}</label> <span class='value'>{{ item.lambert_x }}</span></p> +<p><label>{%trans "Lambert Y:"%}</label> <span class='value'>{{ item.lambert_y }}</span></p> +<p><label>{%trans "Altitude (m NGF):"%}</label> <span class='value'>{{ item.altitude }}</span></p> + +<table> + <caption>{%trans "Associated parcels"%}</caption> + <tr> + <th>{% trans "Commune" %}</th> + <th>{% trans "Year" %}</th> + <th>{% trans "Section" %}</th> + <th>{% trans "Parcel" %}</th> + <th>{% trans "Owner" %}</th> + </tr> + {% for parcels in item.parcel.all %} + <tr> + <td>{{operation.commune}}</td> + <td>{{operation.year}}</td> + <td>{{operation.section}}</td> + <td>{{operation.parcel}}</td> + <td class='string'>{{operation.parcel.owner}}</td> + </tr> + {% empty %} + <tr><td colspan="5" class='no_items'>{% trans "No parcel associated to this operation" %}</td></tr> + {% endfor %} +</table> + +<h3>{% trans "Admninistrative acts"%}</h3> +<table> + <caption>{%trans "Admninistrative acts"%}</caption> + <tr> + <th>{% trans "Year" %}</th> + <th>{% trans "Reference" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "Date" %}</th> + </tr> + {% for act in item.administrative_act.all %} + <tr> + <td>{{act.signature_date.year}}</td> + <td>{{act.ref_sra}}</td> + <td class='string'>{{act.act_type}}</td> + <td>{{act.signature_date}}</td> + </tr> + {% empty %} + <tr><td colspan="4" class='no_items'>{% trans "No administrative act associated to this operation" %}</td></tr> + {% endfor %} +</table> + +<h3>{% trans "Documentation"%}</h3> +<table> + <caption>{%trans "Documents"%}</caption> + <tr> + <th>{% trans "Title" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "Authors" %}</th> + <th>{% trans "Localisation" %}</th> + </tr> + {% for doc in item.doc.all %} + <tr> + <td>{{ doc.title }}</td> + <td class='string'>{{doc.type}}</td> + <td>{{ doc.author.all|join:", " }}</td> + <td>{{ doc.localisation }}</td> + </tr> + {% empty %} + <tr><td colspan="4" class='no_items'>{% trans "No document associated to this operation" %}</td></tr> + {% endfor %} +</table> + +<h3>{% trans "Recording Units"%}</h3> +<table> + <caption>{%trans "Recording Units"%}</caption> + <tr> + <th>{% trans "ID" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "Chronology" %}</th> + <th>{% trans "Description" %}</th> + <th>{% trans "Parcel" %}</th> + <th class='link'> </th> + </tr> + {% for record_unit in item.record_unit.all %} + <tr> + <td>{{ record_unit.label }}</td> + <td class='string'>{{record_unit.unit_type}}</td> + <td>{{ record_unit.period.all|join:", " }}</td> + <td>{{ record_unit.description }}</td> + <td>{{ record_unit.section_and_parcel }}</td><!-- Displayed as (Section)-(parcel number). A record unit can be linked to only one parcel. --> + <td class='link'><a href="#{#{%url show-record_unit record_unit.pk%}#}">{% trans "Details" %}</a></td> + </tr> + {% empty %} + <tr><td colspan="6" class='no_items'>{% trans "No recording unit associated to this operation" %}</td></tr> + {% endfor %} +</table> + +{% endblock %} diff --git a/ishtar_common/templates/sheet_ope_modif.html b/ishtar_common/templates/sheet_ope_modif.html new file mode 100644 index 000000000..cc3a4492e --- /dev/null +++ b/ishtar_common/templates/sheet_ope_modif.html @@ -0,0 +1,182 @@ +{% extends "sheet.html" %} +{% load i18n %} +{% block content %} +<div class='tool'>{%trans "Export as:"%} <a href='{% url show-file item.pk "odt" %}'>{%trans "OpenOffice.org file"%}</a>, <a href='{% url show-file item.pk "pdf" %}'>{%trans "PDF file"%}</a></div> +<h3>{% trans "General"%}</h3> +<p><label>{%trans "Year:"%}</label> <span class='value'>{{ item.year }}</span></p> +<p><label>{%trans "Numerical reference:"%}</label> <span class='value'>{{ item.numeric_reference }}</span></p> + +{% if item.patriarche_code %}<p><label>{%trans "Patriarche OA code:"%}</label> <span class='value'>{{ item.patriarche_code }}</span></p>{%endif%} +{% if item.patriarche_code_not_recorded %}<p><label>{%trans "Patriarche OA code not yet recorded !"%}</label></p>{%endif%} + +<p><label>{%trans "Operation's name:"%}</label> <span class='value'>{{ item.internal_reference }}</span></p> + +<p><label>{%trans "Edition date:"%}</label> <span class='value'>{{ item.history.all.0.history_date }}</span></p> <!-- date = now --> + +<p><label>{%trans "Begining date:"%}</label> <span class='value'>{{ item.begin_date }}</span></p> +<p><label>{%trans "Field work end date:"%}</label> <span class='value'>{{ item.end_date }}</span></p> + +<p><label>{%trans "Head scientist:"%}</label> <span class='value'>{{ item.head_scientist.full_label }}</span></p> +<p><label>{%trans "State:"%}</label> <span class='value'>{% if item.is_active %}{%trans "Active file"%}</span></p> +{% else %}{%trans "Closed operation"%}</span></p> +<p><label>{%trans "Closing date:"%}</label> <span class='value'>{{ item.closing.date }} <strong>{%trans "by" %}</strong> {{ item.closing.user }}</span></p> +{% endif %} +<p><label>{%trans "Type:"%}</label> <span class='value'>{{ item.operation_type }}</span></p> +<p><label>{%trans "Surface:"%}</label> <span class='value'>{{ item.total_surface }} m<sup>2</sup> ({{ item.total_surface_ha }} ha)</span></p> +<p><label>{%trans "Cost:"%}</label> <span class='value'>{{ item.cost }} Euros, ({{ item.cost_by_m2 }} Euros/m<sup>2</sup>)</span></p> +<p><label>{%trans "Duration:"%}</label> <span class='value'>{{ item.duration }} {%trans "Day"%}s</span></p> + +<p><label>{%trans "Remains:"%}</label> <span class='value'>{{ item.remains.all|join:", " }}</span></p> +<p><label>{%trans "Periods:"%}</label> <span class='value'>{{ item.periods.all|join:", " }}</span></p> + +{% if item.related_file %} +<p><label>{%trans "Related file:"%}</label> <span class='value'><a href='{% url show-file item.related_file.pk ''%}'>{{ item.related_file }}</a></span></p><!-- Displayed as Year/index/Commune/Common_name This should be a link to the file sheet of the related file --> +{% if item.related_file.is_preventive %} +{% if item.operator_reference_code %}<p><label>{%trans "Operator's reference code:"%}</label> <span class='value'>{{ item.operator_reference_code }}</span></p>{% endif %} +{% if item.related_file.town_planning_service %}<p><label>{%trans "Town planning service:"%}</label> <span class='value'>{{ item.related_file.town_planning_service }}</span></p>{% endif %} +{% if item.related_file.permit_type %}<p><label>{%trans "Permit type:"%}</label> <span class='value'>{{ item.related_file.permit_type }}</span></p>{% endif %} +{% if item.related_file.permit_reference %}<p><label>{%trans "Permit reference:"%}</label> <span class='value'>{{ item.related_file.permit_reference }}</span></p>{% endif %} +{% if item.related_file.general_contractor.attached_to %}<p><label>{%trans "General contractor organisation:"%}</label> <span class='value'>{{ item.related_file.general_contractor.attached_to }}</span></p>{% endif %} <!-- Contractor's organisation displayed as concat of Name/Adress/postal_code/city --> +{% if item.related_file.general_contractor %}<p><label>{%trans "General contractor:"%}</label> <span class='value'>{{ item.related_file.general_contractor.full_label }}</span></p>{% endif %} +{% endif %} +{% endif %} + +{% if item.comment %}<p><label>{%trans "Comment:"%}</label> <span class='value'>{{ item.comment }}</span></p>{%endif%} + +<h3>{% trans "Localisation"%}</h3> +<p><label>{%trans "Towns:"%}</label> <span class='value'>{{ item.towns.all|join:", " }}</span></p> + +<p><label>{%trans "Main address:"%}</label> <span class='value'>{{ item.address }}</span></p> +{% if item.address_complement %}<p><label>{%trans "Complement:"%}</label> <span class='value'>{{ item.address_complement }}</span></p>{%endif%} +{% if item.postal_code %}<p><label>{%trans "Postal code:"%}</label> <span class='value'>{{ item.postal_code }}</span></p>{%endif%} + +<p><label>{%trans "Lambert X:"%}</label> <span class='value'>{{ item.lambert_x }}</span></p> +<p><label>{%trans "Lambert Y:"%}</label> <span class='value'>{{ item.lambert_y }}</span></p> +<p><label>{%trans "Altitude (m NGF):"%}</label> <span class='value'>{{ item.altitude }}</span></p> + +<table> + <caption>{%trans "Associated parcels"%}</caption> + <tr> + <th>{% trans "Commune" %}</th> + <th>{% trans "Year" %}</th> + <th>{% trans "Section" %}</th> + <th>{% trans "Parcel" %}</th> + <th>{% trans "Owner" %}</th> + </tr> + {% for parcels in item.parcel.all %} + <tr> + <td>{{operation.commune}}</td> + <td>{{operation.year}}</td> + <td>{{operation.section}}</td> + <td>{{operation.parcel}}</td> + <td class='string'>{{operation.parcel.owner}}</td> + </tr> + {% empty %} + <tr><td colspan="5" class='no_items'>{% trans "No parcel associated to this operation" %}</td></tr> + {% endfor %} +</table> + +<h3>{% trans "Admninistrative acts"%}</h3> +<table> + <caption>{%trans "Admninistrative acts"%}</caption> + <tr> + <th>{% trans "Year" %}</th> + <th>{% trans "Reference" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "Date" %}</th> + </tr> + {% for act in item.administrative_act.all %} + <tr> + <td>{{act.signature_date.year}}</td> + <td>{{act.ref_sra}}</td> + <td class='string'>{{act.act_type}}</td> + <td>{{act.signature_date}}</td> + </tr> + {% empty %} + <tr><td colspan="4" class='no_items'>{% trans "No administrative act associated to this operation" %}</td></tr> + {% endfor %} +</table> + +<h3>{% trans "Documentation"%}</h3> +<table> + <caption>{%trans "Documents"%}</caption> + <tr> + <th>{% trans "Title" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "Authors" %}</th> + <th>{% trans "Localisation" %}</th> + </tr> + {% for doc in item.doc.all %} + <tr> + <td>{{ doc.title }}</td> + <td class='string'>{{doc.type}}</td> + <td>{{ doc.author.all|join:", " }}</td> + <td>{{ doc.localisation }}</td> + </tr> + {% empty %} + <tr><td colspan="4" class='no_items'>{% trans "No document associated to this operation" %}</td></tr> + {% endfor %} +</table> + +<h3>{% trans "Recording Units"%}</h3><!-- The list of context units must be listed here --> +<table> + <caption>{%trans "Recording Units"%}</caption> + <tr> + <th>{% trans "ID" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "Chronology" %}</th> + <th>{% trans "Description" %}</th> + <th>{% trans "Parcel" %}</th> + <th class='link'> </th> + </tr> + {% for record_unit in item.record_unit.all %} + <tr> + <td>{{ record_unit.label }}</td> + <td class='string'>{{record_unit.unit_type}}</td> + <td>{{ record_unit.period.all|join:", " }}</td> + <td>{{ record_unit.description }}</td> + <td>{{ record_unit.section_and_parcel }}</td><!-- Displayed as (Section)-(parcel number). A record unit can be linked to only one parcel. --> + <td class='link'><a href="#{#{%url show-record_unit record_unit.pk%}#}">{% trans "Details" %}</a></td> + </tr> + {% empty %} + <tr><td colspan="6" class='no_items'>{% trans "No recording unit associated to this operation" %}</td></tr> + {% endfor %} +</table> + +<h3>{% trans "Finds"%}</h3><!-- The list of finds must be listed here --> +<table> + <caption>{%trans "Finds"%}</caption> + <tr> + <th>{% trans "Find_complete_Label" %}</th> + <th>{% trans "Find_complete_material_type_Label" %}</th> + <th>{% trans "Context_record" %}</th> + <th>{% trans "Periods" %}</th> + <th>{% trans "Description" %}</th> + <th>{% trans "Weight" %}</th> + <th>{% trans "Numbers" %}</th> + <th>{% trans "Parcel" %}</th> + <th class='link'> </th> + </tr> + {% for find in item.find.all %} + <tr> + + {% if item.patriarche_code %}<th>{% trans "find.complete_label" %}</th><!-- Displayed as (Patriarche operation code)-(Record unit label)-(Finds label). -->{%endif%} + {% if item.patriarche_code_not_recorded %}<th>{% trans "find.not_patriarche_complete_label" %}</th><!-- Displayed as (Year)-(index)-(Record unit label)-(Finds label). -->{%endif%} + + {% if item.patriarche_code %}<th>{% trans "find.material_type_complete_label" %}</th><!-- Displayed as (Patriarche operation code)-(Record unit label)-(material code)-(Finds label indexed by material type). -->{%endif%} + {% if item.patriarche_code_not_recorded %}<th>{% trans "find.material_type_not_patriarche_complete_label" %}</th><!-- Displayed as (Year)-(index)-(Record unit label)-(material code)-(Finds label indexed by material type). -->{%endif%} + + <td class='string'>{{find.context_record}}</td> + <td>{{ find.period.all|join:", " }}</td> + <td>{{ find.description }}</td> + <td>{{ find.weight }}</td> + <td>{{ find.numbers }}</td> + <td>{{ find.record_unit.section_and_parcel }}</td><!-- Displayed as (Section)-(parcel number). A record unit can be linked to only one parcel. --> + <td class='link'><a href="#{#{%url show-find find.pk%}#}">{% trans "Details" %}</a></td> + </tr> + {% empty %} + <tr><td colspan="9" class='no_items'>{% trans "No find associated to this operation" %}</td></tr> + {% endfor %} +</table> + +{% endblock %} diff --git a/ishtar_common/templates/sheet_operation.html b/ishtar_common/templates/sheet_operation.html new file mode 100644 index 000000000..aa571d20c --- /dev/null +++ b/ishtar_common/templates/sheet_operation.html @@ -0,0 +1,183 @@ +{% extends "sheet.html" %} +{% load i18n %} +{% block content %} +<div class='tool'>{%trans "Export as:"%} <a href='{% url show-operation item.pk "odt" %}'>{%trans "OpenOffice.org file"%}</a>, <a href='{% url show-operation item.pk "pdf" %}'>{%trans "PDF file"%}</a></div> +<h3>{% trans "General"%}</h3> +<p><label>{%trans "Year:"%}</label> <span class='value'>{{ item.year }}</span></p> +<p><label>{%trans "Numerical reference:"%}</label> <span class='value'>{{ item.operation_code }}</span></p> + +{% if item.code_patriarche %}<p><label>{%trans "Patriarche OA code:"%}</label> <span class='value'>{{ item.code_patriarche }}</span></p>{%else%} +<p class='alert'>{%trans "Patriarche OA code not yet recorded!"%}</p>{%endif%} + +{#<p><label>{%trans "Operation's name:"%}</label> <span class='value'>{{ item.internal_reference }}</span></p>#} + +<p><label>{%trans "Edition date:"%}</label> <span class='value'>{{ item.history.all.0.history_date }}</span></p> <!-- date = now --> + +{% if item.start_date %}<p><label>{%trans "Begining date:"%}</label> <span class='value'>{{ item.start_date }}</span></p> +<p><label>{%trans "Excavation end date:"%}</label> <span class='value'>{{ item.excavation_end_date|default:"-" }}</span></p> +{%endif%} +{% if item.in_charge %}<p><label>{%trans "Head scientist:"%}</label> <span class='value'>{{ item.in_charge.full_label }}</span></p>{%endif%} +<p><label>{%trans "State:"%}</label> <span class='value'>{% if item.is_active %}{%trans "Active file"%}</span></p> +{% else %}{%trans "Closed operation"%}</span></p> +<p><label>{%trans "Closing date:"%}</label> <span class='value'>{{ item.closing.date }} <strong>{%trans "by" %}</strong> {{ item.closing.user }}</span></p> +{% endif %} +<p><label>{%trans "Type:"%}</label> <span class='value'>{{ item.operation_type }}</span></p> +{% if item.surface %}<p><label>{%trans "Surface:"%}</label> <span class='value'>{{ item.surface }} m<sup>2</sup> ({{ item.surface_ha }} ha)</span></p>{% endif %} +{% if item.cost %}<p><label>{%trans "Cost:"%}</label> <span class='value'>{{ item.cost }} €{% if item.cost_by_m2 %}, ({{ item.cost_by_m2 }} €/m<sup>2</sup>){%endif%}</span></p>{%endif%} +{% if item.duration %}<p><label>{%trans "Duration:"%}</label> <span class='value'>{{ item.duration }} {%trans "Day"%}s</span></p>{%endif%} + +<p><label>{%trans "Remains:"%}</label> <span class='value'>{{ item.remains.all|join:", " }}</span></p> +<p><label>{%trans "Periods:"%}</label> <span class='value'>{{ item.periods.all|join:", " }}</span></p> + +{% if item.associated_file %} +<p><label>{%trans "Associated file:"%}</label> <span class='value'><a href='#' onclick='load_window("{% url show-file item.associated_file.pk ''%}")'>{{ item.associated_file }}</a></span></p><!-- Displayed as Year/index/Commune/Common_name This should be a link to the file sheet of the related file --> +{% if item.associated_file.is_preventive %} +{#{% if item.operator_reference_code %}<p><label>{%trans "Operator's reference code:"%}</label> <span class='value'>{{ item.operator_reference_code }}</span></p>{% endif %}#} +{% if item.associated_file.town_planning_service %}<p><label>{%trans "Town planning service:"%}</label> <span class='value'>{{ item.associated_file.town_planning_service }}</span></p>{% endif %} +{% if item.associated_file.permit_type %}<p><label>{%trans "Permit type:"%}</label> <span class='value'>{{ item.associated_file.permit_type }}</span></p>{% endif %} +{% if item.associated_file.permit_reference %}<p><label>{%trans "Permit reference:"%}</label> <span class='value'>{{ item.associated_file.permit_reference }}</span></p>{% endif %} +{% if item.associated_file.general_contractor.attached_to %}<p><label>{%trans "General contractor organisation:"%}</label> <span class='value'>{{ item.associated_file.general_contractor.attached_to }}</span></p>{% endif %} <!-- Contractor's organisation displayed as concat of Name/Adress/postal_code/city --> +{% if item.associated_file.general_contractor %}<p><label>{%trans "General contractor:"%}</label> <span class='value'>{{ item.associated_file.general_contractor.full_label }}</span></p>{% endif %} +{% endif %} +{% endif %} + +{% if item.comment %}<p><label>{%trans "Comment:"%}</label> <span class='value'>{{ item.comment }}</span></p>{%endif%} + +<h3>{% trans "Localisation"%}</h3> +<p><label>{%trans "Towns:"%}</label> <span class='value'>{{ item.towns.all|join:", " }}</span></p> + +<p><label>{%trans "Main address:"%}</label> <span class='value'>{{ item.associated_file.address }}</span></p> +{% if item.associated_file.address_complement %}<p><label>{%trans "Complement:"%}</label> <span class='value'>{{ item.associated_file.address_complement }}</span></p>{%endif%} +{% if item.associated_file.postal_code %}<p><label>{%trans "Postal code:"%}</label> <span class='value'>{{ item.associated_file.postal_code }}</span></p>{%endif%} + +{% comment %} +<p><label>{%trans "Lambert X:"%}</label> <span class='value'>{{ item.lambert_x }}</span></p> +<p><label>{%trans "Lambert Y:"%}</label> <span class='value'>{{ item.lambert_y }}</span></p> +<p><label>{%trans "Altitude (m NGF):"%}</label> <span class='value'>{{ item.altitude }}</span></p> +{% endcomment %} +<table> + <caption>{%trans "Associated parcels"%}</caption> + <tr> + <th>{% trans "Commune" %}</th> + <th>{% trans "Year" %}</th> + <th>{% trans "Section" %}</th> + <th>{% trans "Parcel" %}</th> + {#<th>{% trans "Owner" %}</th>#} + </tr> + {% for parcel in item.parcels.all %} + <tr> + <td class='string'>{{parcel.town}}</td> + <td>{{parcel.year}}</td> + <td>{{parcel.section}}</td> + <td>{{parcel.parcel_number}}</td> + {#<td class='string'>{{operation.parcel.owner}}</td>#} + </tr> + {% empty %} + <tr><td colspan="4" class='no_items'>{% trans "No parcel associated to this operation" %}</td></tr> + {% endfor %} +</table> + +<table> + <caption>{%trans "Admninistrative acts"%}</caption> + <tr> + <th>{% trans "Year" %}</th> + <th>{% trans "Reference" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "Date" %}</th> + </tr> + {% for act in item.administrative_act.all %} + <tr> + <td>{{act.signature_date.year}}</td> + <td>{{act.ref_sra}}</td> + <td class='string'>{{act.act_type}}</td> + <td class="string">{{act.signature_date}}</td> + </tr> + {% empty %} + <tr><td colspan="4" class='no_items'>{% trans "No acts associated to this operation" %}</td></tr> + {% endfor %} +</table> + +<h3>{% trans "Scientific documentation"%}</h3> +<table> + <caption>{%trans "Documents"%}</caption> + <tr> + <th>{% trans "Title" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "Authors" %}</th> + {#<th>{% trans "Localisation" %}</th>#} + </tr> + {% for doc in item.source.all %} + <tr> + <td class='string'>{{ doc.title }}</td> + <td class='string'>{{doc.source_type}}</td> + <td class='string'>{{ doc.authors.all|join:", " }}</td> + {#<td>{{ doc.localisation }}</td>#} + </tr> + {% empty %} + <tr><td colspan="4" class='no_items'>{% trans "No scientific document associated to this operation" %}</td></tr> + {% endfor %} +</table> + +<table> + <caption>{%trans "Context records"%}</caption> + <tr> + <th>{% trans "ID" %}</th> + <th>{% trans "Type" %}</th> + <th>{% trans "Chronology" %}</th> + <th>{% trans "Description" %}</th> + <th>{% trans "Parcel" %}</th> + <th class='link'> </th> + </tr> + {% for context_record in item.context_record.all %} + <tr> + <td class='string'>{{ context_record.label }}</td> + <td class='string'>{{context_record.unit|default:""}}</td> + <td class='string'>{{ context_record.datings.all|join:", " }}</td>{# periods ?#} + <td class='string'>{{ context_record.description }}</td> + <td class='string'>{{ context_record.parcel.section }} - {{context_record.parcel.parcel_number}}</td> + <td class='link'><a href="#" onclick='load_window("{%url show-contextrecord context_record.pk ''%}")'>{% trans "Details" %}</a></td> + </tr> + {% empty %} + <tr><td colspan="6" class='no_items'>{% trans "No context record associated to this operation" %}</td></tr> + {% endfor %} +</table> +<div class='table'> +<table> + <caption>{%trans "Finds"%}</caption> + <tr> + <th>{% trans "Find" %}</th> + <th>{% trans "Material type" %}</th> + <th>{% trans "Context record" %}</th> + <th>{% trans "Periods" %}</th> + <th>{% trans "Description" %}</th> + <th>{% trans "Weight" %}</th> + <th>{% trans "Numbers" %}</th> + <th>{% trans "Parcel" %}</th> + <th class='link'> </th> + </tr> + {% for context_record in item.context_record.all %} + {% for find in context_record.base_items.all %} + <tr> + <td class="ref">{{ find.full_label }}</td> +{# Displayed as (Patriarche operation code)-(Record unit label)-(Finds label). #} +{# or displayed as (Year)-(index)-(Record unit label)-(Finds label). #} + <td class="ref">{{ find.material_type_label }}</td> + <td>{{find.context_record.label}}</td> + <td class='string'>{{ find.get_last_item.dating}}</td>{# TODO .all|join:", " ? #} + <td class='string'>{{ find.get_last_item.description }}</td> + <td>{{ find.get_last_item.weight }}</td> + <td>{{ find.get_last_item.item_number }}</td> + <td class="ref">{{ context_record.parcel.short_label }}</td> + <td class='link'><a href="#">{% trans "Details" %}</a></td> + {#<a href="#" onclick='load_window("{% url show-find find.pk%}");'>{%trans "Details"%}</a></td>#} + </tr> + {% empty %} + <tr><td colspan="9" class='no_items'>{% trans "No find associated to context record" %} {{context_record.short_label}}</td></tr> + {% endfor %} + {% empty %} + <tr><td colspan="9" class='no_items'>{% trans "No find associated to parcel" %} {{parcel.short_label}} {% trans "(no context record)" %}</td></tr> + {% endfor %} +</table> +</div> + +{% endblock %} diff --git a/ishtar_common/templates/sheet_operation_pdf.html b/ishtar_common/templates/sheet_operation_pdf.html new file mode 100644 index 000000000..3397d5f43 --- /dev/null +++ b/ishtar_common/templates/sheet_operation_pdf.html @@ -0,0 +1,18 @@ +{% extends "sheet_operation.html" %} +{% block css_head %} +<link rel="stylesheet" href="{{MEDIA_URL}}/media/style_basic.css" /> +{% endblock %} +{% block main_head %} +{{ block.super }} +<div id="pdfheader"> +Ishtar – {{APP_NAME}} – {{item}} +</div> +{% endblock %} +{%block head_sheet%}{%endblock%} +{%block main_foot%} +<div id="pdffooter"> +– <pdf:pagenumber/> – +</div> +</body> +</html> +{%endblock%} diff --git a/ishtar_common/templates/sheet_operation_window.html b/ishtar_common/templates/sheet_operation_window.html new file mode 100644 index 000000000..9c595a1e9 --- /dev/null +++ b/ishtar_common/templates/sheet_operation_window.html @@ -0,0 +1,3 @@ +{% extends "sheet_operation.html" %} +{% block main_head %}{%endblock%} +{% block main_foot %}{%endblock%} diff --git a/ishtar_common/templates/towns_wizard.html b/ishtar_common/templates/towns_wizard.html new file mode 100644 index 000000000..115ac9838 --- /dev/null +++ b/ishtar_common/templates/towns_wizard.html @@ -0,0 +1,40 @@ +{% extends "default_wizard.html" %} +{% load i18n %} +{% load range %} +{% block extra_head %} +{{form.media}} +{% endblock %} +{% block content %} +<form action="." method="post" name='wizard'>{% csrf_token %} +<ul id='form_path'> +{% for step in previous_steps %} + <li>» <button name="form_prev_step" value="{{forloop.counter0}}">{{step.form_label}}</button></li> +{% endfor %} + <li class='current'>» <a href='#'>{{current_step.form_label}}</a></li> +</ul> +<div class='form'> +{% if extra_context.TOWNS %} +{% if form.forms %} +<div class='top_button'><input type="submit" id="submit_form" value="{% trans "Validate" %}"/></div> +<table class='formset'> + {%if form.non_form_errors%}<tr class='error'><th colspan='2'>{{form.non_form_errors}}</th></tr>{%endif%} + {{ form.management_form }} + {% for formsetform in form.forms %} + {{ formsetform.as_table }} + {% endfor %} + <tr class='modify'><td colspan="2"><button name="formset_modify" value="{{form_step}}">{% trans "Add/Modify" %}</button></td></tr></li> +</table> +{% else %} +<table> + {{ form.as_table }} +</table> +{% endif %} +{% else %} +<p class='alert'>{% trans "No town set in the associated file." %}</p> +{% endif %} +<input type="hidden" name="{{ step_field }}" value="{{ step0 }}" /> +{{ previous_fields|safe }} +<input type="submit" id="submit_form" value="{% trans "Validate" %}"/> +</div> +</form> +{% endblock %} diff --git a/ishtar_common/templates/window.html b/ishtar_common/templates/window.html new file mode 100644 index 000000000..a92f859ab --- /dev/null +++ b/ishtar_common/templates/window.html @@ -0,0 +1,45 @@ +{% load i18n %} +<!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> + <link rel="shortcut icon" href="{{MEDIA_URL}}/media/images/favicon.png"> + <title>{% block title %}Ishtar{% if APP_NAME %} - {{APP_NAME}}{%endif%}{% endblock %} + </title> + <script language="javascript" type="text/javascript"> + var url_path = "{{URL_PATH}}"; + </script> + <script language="javascript" type="text/javascript" src="{{JQUERY_URL}}"></script> + <script language="javascript" type="text/javascript" src="{{JQUERY_UI_URL}}jquery-ui.js"></script> + <script language="javascript" type="text/javascript" src="{{JQUERY_UI_URL}}ui/i18n/jquery.ui.datepicker-{{COUNTRY}}.js"></script> + <script language="javascript" type="text/javascript" src="{{MEDIA_URL}}/js/ishtar.js"></script> + <link type="text/css" href="{{JQUERY_UI_URL}}css/smoothness/jquery-ui.css" rel="stylesheet" /> + <link rel="stylesheet" href="{{MEDIA_URL}}/media/style.css" /> + {% block extra_head %} + {% endblock %} +</head> +<body> +{% if new_item_label %} +<script type='text/javascript' language='javascript'> +save_and_close_window("{{parent_name}}", "{{parent_pk}}", "{{new_item_label}}", "{{new_item_pk}}"); +</script> +{% endif %} +<div id="window_content"> + <h3>{{title}}</h3> + <form action="." method="post" class='form'>{% csrf_token %} + <table> + {% for field in form %} + <tr{% if field.field.required %} class='required'{% endif %}> + <th><label for="{{ field.label }}">{{ field.label_tag }}</th> + <td> {{ field.errors }}{{field|safe}}</td> + </tr>{% endfor %} + <tr><td colspan='2' class='submit_button'><input type="submit" id="submit_new_item" value="{% trans "Add" %}"/></td></tr> + </table> + </form> + </div> + +</div> +</body> + +</html> diff --git a/ishtar_common/templates/wizard_closing_done.html b/ishtar_common/templates/wizard_closing_done.html new file mode 100644 index 000000000..54990a629 --- /dev/null +++ b/ishtar_common/templates/wizard_closing_done.html @@ -0,0 +1,6 @@ +{% extends "base.html" %} +{% load i18n %} +{% block content %} +<p>{%trans "Item successfully closed"%}</p> +</div> +{% endblock %} diff --git a/ishtar_common/templates/wizard_delete_done.html b/ishtar_common/templates/wizard_delete_done.html new file mode 100644 index 000000000..854341aa3 --- /dev/null +++ b/ishtar_common/templates/wizard_delete_done.html @@ -0,0 +1,6 @@ +{% extends "base.html" %} +{% load i18n %} +{% block content %} +<p>{%trans "Item successfully deleted"%}</p> +</div> +{% endblock %} diff --git a/ishtar_common/templates/wizard_done.html b/ishtar_common/templates/wizard_done.html new file mode 100644 index 000000000..a7068bbab --- /dev/null +++ b/ishtar_common/templates/wizard_done.html @@ -0,0 +1,6 @@ +{% extends "base.html" %} +{% load i18n %} +{% block content %} +<p>{%trans "Item successfully saved"%}</p> +</div> +{% endblock %} diff --git a/ishtar_common/templates/wizard_done_summary.html b/ishtar_common/templates/wizard_done_summary.html new file mode 100644 index 000000000..53650dafe --- /dev/null +++ b/ishtar_common/templates/wizard_done_summary.html @@ -0,0 +1,18 @@ +{% extends "wizard_done.html" %} +{% load i18n %} +{% block content %} + +<div class='form'> + <p>{% trans "You have entered the following informations:" %}</p> + {% for form_label, form_data in datas %} + <table class='confirm'> + <caption>{{form_label}}</caption> + {% for label, data, cls in form_data %} + <tr{%if cls%} class='{{cls}}'{%endif%}><th>{{label}}</th><td>{{data}}</td></th> + {% endfor %} + </table> + {% endfor %} + <p>{% trans {%trans "Item successfully saved"%} %}</p> +</div> + +{% endblock %} diff --git a/ishtar_common/templates/wizard_done_summary_2.html b/ishtar_common/templates/wizard_done_summary_2.html new file mode 100644 index 000000000..66a572542 --- /dev/null +++ b/ishtar_common/templates/wizard_done_summary_2.html @@ -0,0 +1,23 @@ +{% extends "wizard_done.html" %} +{% load i18n %} +{% block content %} + +<div class='form'> + <p>{% trans {%trans "Item successfully saved"%} %}</p> + <p>{% trans "You have saved the following informations:" %}</p> + <p>{% trans {%trans "The file must be processed before :"%} %} {% calculated_deadline %} </p> + <p>{% trans {%trans "The person in charge is : "%} %} {% responsible %} </p> + <p>{% trans {%trans "The internal reference of this file is :"%} %} {% Year %} - {% ref_index %} [{% ref_string %}]</p> + + {% for form_label, form_data in datas %} + <table class='confirm'> + <caption>{{form_label}}</caption> + {% for label, data, cls in form_data %} + <tr{%if cls%} class='{{cls}}'{%endif%}><th>{{label}}</th><td>{{data}}</td></th> + {% endfor %} + </table> + {% endfor %} + +</div> + +{% endblock %} diff --git a/ishtar_common/templates/wizard_list_search_result.html b/ishtar_common/templates/wizard_list_search_result.html new file mode 100644 index 000000000..6cbafb930 --- /dev/null +++ b/ishtar_common/templates/wizard_list_search_result.html @@ -0,0 +1,25 @@ +{% extends "wizard_done.html" %} +{% load i18n %} +{% block content %} + +<div class='form'> + <p>{% trans {%trans "PLease note that the file must be processed before :"%} %} {% calculated_deadline %} </p> + + <p>{% trans {%trans "Item successfully saved"%} %}</p> + <p>{% trans "You have saved the following informations:" %}</p> + + <p>{% trans {%trans "The person in charge is : "%} %} {% responsible %} </p> + <p>{% trans {%trans "The internal reference of this file is :"%} %} {% Year %} - {% ref_index %} [{% ref_string %}]</p> + + {% for form_label, form_data in datas %} + <table class='confirm'> + <caption>{{form_label}}</caption> + {% for label, data, cls in form_data %} + <tr{%if cls%} class='{{cls}}'{%endif%}><th>{{label}}</th><td>{{data}}</td></th> + {% endfor %} + </table> + {% endfor %} + +</div> + +{% endblock %} diff --git a/ishtar_common/templatetags/__init__.py b/ishtar_common/templatetags/__init__.py new file mode 100644 index 000000000..792d60054 --- /dev/null +++ b/ishtar_common/templatetags/__init__.py @@ -0,0 +1 @@ +# diff --git a/ishtar_common/templatetags/range.py b/ishtar_common/templatetags/range.py new file mode 100644 index 000000000..3b3a9097b --- /dev/null +++ b/ishtar_common/templatetags/range.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from django.template import Library + +register = Library() + +@register.filter +def get_range(value): + return [val+1 for val in xrange(value)] diff --git a/ishtar_common/templatetags/table_form.py b/ishtar_common/templatetags/table_form.py new file mode 100644 index 000000000..7adb54d65 --- /dev/null +++ b/ishtar_common/templatetags/table_form.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from django.template import Library + +register = Library() + +@register.inclusion_tag('form_snippet.html') +def table_form(form): + return {'form': form} diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py new file mode 100644 index 000000000..5a433b381 --- /dev/null +++ b/ishtar_common/tests.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +""" +Unit tests +""" +import json + +from django.test import TestCase + +import models + +class FileTest(TestCase): + fixtures = ['user.json', 'person_type-fr.json', 'organization_type-fr.json', + 'treatment_type-fr.json'] + model = models.File + + def setUp(self): + self.extra_models, self.model_list = {}, [] + user = models.IshtarUser.objects.get(pk=1) + person_type = models.PersonType(label=u'Test person type', + txt_idx='test_person', available=True) + person_type.save() + self.extra_models['person_type'] = person_type + self.model_list.append(person_type) + + person = models.Person(title='Mr', surname='Surname', name='Name', + person_type=person_type, history_modifier=user) + person.save() + self.extra_models['person'] = person + self.model_list.append(person) + + file_type = models.FileType(label=u'Test file type', + txt_idx='test_file', available=True) + file_type.save() + self.extra_models['file_type'] = file_type + self.model_list.append(file_type) + + dct = {'year':2010, 'numeric_reference':1000, 'file_type':file_type, + 'internal_reference':u'UNIT_testÉ ?', 'in_charge':person, + 'history_modifier':user, 'total_surface':10000} + self.item = self.model(**dct) + self.item.save() + + def tearDown(self): + self.item.delete() + for item in reversed(self.model_list): + item.delete() + + def testAddAndGetHistorized(self): + """ + Test correct new version and correct access to history + """ + nb_hist = self.item.history.count() + self.assertTrue(self.item.history.count() >= 1) + base_label = self.item.internal_reference + self.item.internal_reference = u"Unité_Test" + self.item.save() + self.failUnlessEqual(self.item.history.count(), nb_hist+1) + self.failUnlessEqual(self.item.history.all()[1].internal_reference, + base_label) + + def testIntelligentHistorisation(self): + """ + Test that to identical version are not recorded twice in the history + """ + nb_hist = self.item.history.count() + self.item.internal_reference = u"Unité_Test" + self.item.save() + self.failUnlessEqual(self.item.history.count(), nb_hist+1) + nb_hist = self.item.history.count() + self.item.save() + self.failUnlessEqual(self.item.history.count(), nb_hist) + + def testRollbackFile(self): + nb_hist = self.item.history.count() + initial_values = self.item.values() + backup_date = self.item.history.all()[0].history_date + self.item.internal_reference = u"Unité_Test" + self.item.save() + self.item.rollback(backup_date) + self.failUnlessEqual(self.item.history.count(), nb_hist) + new_values = self.item.values() + for k in initial_values.keys(): + self.assertTrue(k in new_values) + self.assertEqual(new_values[k], initial_values[k]) + + def testRESTGetFile(self): + response = self.client.post('/get-file/', + {'numeric_reference':self.item.numeric_reference}) + self.assertEqual(response.status_code, 200) + data = json.loads(response.content) + self.assertTrue('records' in data) + self.assertTrue(data['records'] == 1) + + def testRESTGetOldFile(self): + initial_ref = self.item.internal_reference + new_ref = u"Unité_Test_old_file" + new_ref = initial_ref != new_ref and new_ref or new_ref + u"extra" + self.item.internal_reference = new_ref + self.item.save() + response = self.client.post('/get-file/', + {'numeric_reference':self.item.numeric_reference, 'old':1}) + self.assertEqual(response.status_code, 200) + data = json.loads(response.content) + self.assertTrue('records' in data) + self.assertTrue(data['records'] == 1) + self.assertEqual(data['rows'][0]['internal_reference'], initial_ref) + diff --git a/ishtar_common/urls.py b/ishtar_common/urls.py new file mode 100644 index 000000000..437a6bbb4 --- /dev/null +++ b/ishtar_common/urls.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +from django.conf.urls.defaults import * + +from menus import menu +#import forms_main as ishtar_forms + +import views + +urlpatterns, actions = [], [] + + +# forms +urlpatterns = patterns('', + # General + url(r'person_creation/(?P<step>.+)$', + views.person_creation_wizard, name='person_creation_step'), + url(r'person_creation/$', + views.person_creation_wizard, name='person_creation'), + ) +""" + url(r'person_modification/(?P<step>.+)$', + ishtar_forms.person_modification_wizard, name='person_modification'), + url(r'account_management/(?P<step>.+)$', + ishtar_forms.account_management_wizard, name='account_management'), + # Archaelogical files + url(r'file_search/(?P<step>.+)$', + ishtar_forms.file_search_wizard, name='file_search'), + url(r'file_creation/(?P<step>.+)$', + ishtar_forms.file_creation_wizard, name='file_creation'), + url(r'file_modification/(?P<step>.+)$', + ishtar_forms.file_modification_wizard, name='file_modification'), + url(r'file_closing/(?P<step>.+)$', + ishtar_forms.file_closing_wizard, name='file_closing'), + url(r'file_deletion/(?P<step>.+)$', + ishtar_forms.file_deletion_wizard, name='file_deletion'), + url(r'file_administrativeactfile/(?P<step>.+)$', + ishtar_forms.file_administrativeactfile_wizard, + name='file_administrativeactfile'), + url(r'file_administrativeactfile_modification/(?P<step>.+)$', + ishtar_forms.file_administrativeactfile_modification_wizard, + name='file_administrativeactfile_modification'), + url(r'file_administrativeactfile_deletion/(?P<step>.+)$', + ishtar_forms.file_administrativeactfile_deletion_wizard, + name='file_administrativeactfile_deletion'), + # Operations + url(r'operation_search/(?P<step>.+)$', + ishtar_forms.operation_search_wizard, name='operation_search'), + url(r'operation_creation/(?P<step>.+)$', + ishtar_forms.operation_creation_wizard, name='operation_creation'), + url(r'operation_modification/(?P<step>.+)$', + ishtar_forms.operation_modification_wizard, + name='operation_modification'), + url(r'operation_closing/(?P<step>.+)$', + ishtar_forms.operation_closing_wizard, name='operation_closing'), + url(r'operation_deletion/(?P<step>.+)$', + ishtar_forms.operation_deletion_wizard, name='operation_deletion'), + url(r'operation_administrativeactop/(?P<step>.+)$', + ishtar_forms.operation_administrativeactop_wizard, + name='operation_administrativeactop'), + url(r'operation_administrativeactop_modification/(?P<step>.+)$', + ishtar_forms.operation_administrativeactop_modification_wizard, + name='operation_administrativeactop_modification'), + url(r'operation_administrativeactop_deletion/(?P<step>.+)$', + ishtar_forms.operation_administrativeactop_deletion_wizard, + name='operation_administrativeactop_deletion'), + url(r'operation_source_creation/(?P<step>.+)$', + ishtar_forms.operation_source_creation_wizard, + name='operation_source_creation'), + url(r'operation_source_modification/(?P<step>.+)$', + ishtar_forms.operation_source_modification_wizard, + name='operation_source_modification'), + url(r'operation_source_deletion/(?P<step>.+)$', + ishtar_forms.operation_source_deletion_wizard, + name='operation_source_deletion'), + # Context records + url(r'record_search/(?P<step>.+)$', + ishtar_forms.record_search_wizard, name='record_search'), + url(r'record_creation/(?P<step>.+)$', + ishtar_forms.record_creation_wizard, name='record_creation'), + url(r'record_modification/(?P<step>.+)$', + ishtar_forms.record_modification_wizard, name='record_modification'), + url(r'record_deletion/(?P<step>.+)$', + ishtar_forms.record_deletion_wizard, name='record_deletion'), + url(r'record_source_creation/(?P<step>.+)$', + ishtar_forms.record_source_creation_wizard, + name='record_source_creation'), + url(r'record_source_modification/(?P<step>.+)$', + ishtar_forms.record_source_modification_wizard, + name='record_source_modification'), + url(r'record_source_deletion/(?P<step>.+)$', + ishtar_forms.record_source_deletion_wizard, + name='record_source_deletion'), + # Finds + url(r'item_search/(?P<step>.+)$', + ishtar_forms.item_search_wizard, name='item_search'), + url(r'item_creation/(?P<step>.+)$', + ishtar_forms.item_creation_wizard, name='item_creation'), + url(r'item_modification/(?P<step>.+)$', + ishtar_forms.item_modification_wizard, name='item_modification'), + url(r'item_source_creation/(?P<step>.+)$', + ishtar_forms.item_source_creation_wizard, + name='item_source_creation'), + url(r'item_source_modification/(?P<step>.+)$', + ishtar_forms.item_source_modification_wizard, + name='item_source_modification'), + url(r'item_source_deletion/(?P<step>.+)$', + ishtar_forms.item_source_deletion_wizard, + name='item_source_deletion'), + # Treatments + url(r'treatment_creation/(?P<step>.+)$', + ishtar_forms.treatment_creation_wizard, name='treatment_creation'), + url(r'warehouse_packaging/(?P<step>.+)$', + ishtar_forms.warehouse_packaging_wizard, name='warehouse_packaging'), + )""" +for section in menu.childs: + for menu_item in section.childs: + if hasattr(menu_item, 'childs'): + for menu_subitem in menu_item.childs: + actions.append(menu_subitem.idx) + else: + actions.append(menu_item.idx) +actions = r"|".join(actions) + +# other views +urlpatterns += patterns('ishtar_common.views', + # General + url(r'(?P<action_slug>' + actions + r')/$', 'action', + name='action'), + url(r'new-person/(?P<parent_name>.+)?/$', + 'new_person', name='new-person'), + url(r'autocomplete-person/([0-9_]+)?$', 'autocomplete_person', + name='autocomplete-person'), + url(r'autocomplete-town/$', 'autocomplete_town', + name='autocomplete-town'), + url(r'new-author/(?P<parent_name>.+)?/$', + 'new_author', name='new-author'), + url(r'autocomplete-author/$', 'autocomplete_author', + name='autocomplete-author'), + url(r'new-organization/(?P<parent_name>.+)?/$', + 'new_organization', name='new-organization'), + url(r'autocomplete-organization/([0-9_]+)?$', + 'autocomplete_organization', name='autocomplete-organization'), + url(r'new-warehouse/(?P<parent_name>.+)?/$', + 'new_warehouse', name='new-warehouse'), + url(r'autocomplete-warehouse/$', 'autocomplete_warehouse', + name='autocomplete-warehouse'), + # Archaelogical files + url(r'autocomplete-file/$', 'autocomplete_file', + name='autocomplete-file'), + url(r'get-file/(?P<type>.+)?$', 'get_file', + name='get-file'), + url(r'get-file-full/(?P<type>.+)?$', 'get_file', + name='get-file-full', kwargs={'full':True}), + url(r'get-administrativeactfile/(?P<type>.+)?$', + 'get_administrativeactfile', name='get-administrativeactfile'), + url(r'show-file/(?P<pk>.+)?/(?P<type>.+)?$', 'show_file', + name='show-file'), + url(r'show-historized-file/(?P<pk>.+)?/(?P<date>.+)?$', + 'show_file', name='show-historized-file'), + url(r'revert-file/(?P<pk>.+)/(?P<date>.+)$', + 'revert_file', name='revert-file'), + # Operations + url(r'autocomplete-operation/$', 'autocomplete_operation', + name='autocomplete-operation'), + url(r'get-operation/(?P<type>.+)?$', 'get_operation', + name='get-operation'), + url(r'get-operation-full/(?P<type>.+)?$', 'get_operation', + name='get-operation-full', kwargs={'full':True}), + url(r'get-available-operation-code/(?P<year>.+)?$', + 'get_available_operation_code', name='get_available_operation_code'), + url(r'revert-operation/(?P<pk>.+)/(?P<date>.+)$', + 'revert_operation', name='revert-operation'), + url(r'show-operation/(?P<pk>.+)?/(?P<type>.+)?$', + 'show_operation', name='show-operation'), + url(r'get-administrativeactop/(?P<type>.+)?$', + 'get_administrativeactop', name='get-administrativeactop'), + url(r'get-operationsource/(?P<type>.+)?$', + 'get_operationsource', name='get-operationsource'), + # Context records + url(r'show-contextrecord/(?P<pk>.+)?/(?P<type>.+)?$', + 'show_contextrecord', name='show-contextrecord'), + url(r'get-contextrecord/(?P<type>.+)?$', 'get_contextrecord', + name='get-contextrecord'), + url(r'get-contextrecord-full/(?P<type>.+)?$', + 'get_contextrecord', name='get-contextrecord-full', + kwargs={'full':True}), + url(r'get-contexrecordsource/(?P<type>.+)?$', + 'get_contextrecordsource', name='get-contextrecordsource'), + # Finds + url(r'update-current-item/$', 'update_current_item', + name='update-current-item'), + url(r'get-item/(?P<type>.+)?$', 'get_archaeologicalitem', + name='get-item'), + url(r'get-item-full/(?P<type>.+)?$', 'get_archaeologicalitem', + name='get-item-full', kwargs={'full':True}), + url(r'get-itemsource/(?P<type>.+)?$', + 'get_itemsource', name='get-itemsource'), + url(r'get-container/$', 'get_container', + name='get-container'), + # Treatments + url(r'autocomplete-container/?$', + 'autocomplete_container', name='autocomplete-container'), + url(r'new-container/(?P<parent_name>.+)?/$', + 'new_container', name='new-container'), +) diff --git a/ishtar_common/views.py b/ishtar_common/views.py new file mode 100644 index 000000000..9b06276f8 --- /dev/null +++ b/ishtar_common/views.py @@ -0,0 +1,1333 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (C) 2010-2011 É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 +# 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 Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# See the file COPYING for details. + +try: + import tidy +except: + from tidylib import tidy_document as tidy + +import re +import csv +import json +import datetime +import optparse +import cStringIO as StringIO +from tempfile import NamedTemporaryFile +import ho.pisa as pisa + +from django.conf import settings +from django.contrib.formtools.wizard.views import NamedUrlWizardView +from django.core import serializers +from django.core.exceptions import ObjectDoesNotExist +from django.core.urlresolvers import reverse, NoReverseMatch +from django.db.models import Q +from django.http import HttpResponse, Http404 +from django.shortcuts import render_to_response, redirect +from django.template import RequestContext, loader +from django.template.defaultfilters import slugify +from django.utils.translation import ugettext, ugettext_lazy as _ + +if settings.XHTML2ODT_PATH: + import sys + sys.path.append(settings.XHTML2ODT_PATH) + from xhtml2odt import xhtml2odt + +from menus import menu +import forms_main as ishtar_forms + +from ishtar_common.forms import FinalForm +from ishtar_common.forms_common import PersonForm +import models + +CSV_OPTIONS = {'delimiter':';', 'quotechar':'"', 'quoting':csv.QUOTE_ALL} +ENCODING = settings.ENCODING or 'utf-8' + +def index(request): + """ + Main page + """ + dct = {} + return render_to_response('index.html', dct, + context_instance=RequestContext(request)) + +class Wizard(NamedUrlWizardView): + model = None + modification = None # True when the wizard modify an item + storage_name = 'django.contrib.formtools.wizard.storage.session.SessionStorage' + + @staticmethod + def _check_right(step, condition=True): + '''Return a method to check the right for a specific step''' + """ + def check_right(self, request, storage): + cond = condition + if callable(condition): + cond = condition(self, request, storage) + if not cond: + return False + person_type = request.user.ishtaruser.person.person_type + if person_type.txt_idx == 'administrator': + return True + if person_type.rights.filter(url_name=step).count(): + return True""" + def check_right(self): + cond = condition + if callable(condition): + cond = condition(self) + if not cond: + return False + person_type = self.request.user.ishtaruser.person.person_type + if person_type.txt_idx == 'administrator': + return True + if person_type.rights.filter(url_name=step).count(): + return True + return check_right + + def __init__(self, *args, **kwargs): + """Check right for each step of the wizard""" + super(Wizard, self).__init__(*args, **kwargs) + for form_key in self.form_list.keys()[:-1]: + condition = True + if form_key in self.condition_dict: + condition = self.condition_dict.get(form_key, True) + cond = self._check_right(form_key, condition) + self.condition_dict[form_key] = cond + """ + for form_key in self.form_list.keys()[:-1]: + condition = True + if form_key in self.condition_list: + condition = self.condition_list.get(form_key, True) + cond = self._check_right(form_key, condition) + self.condition_list[form_key] = cond""" + + def get_wizard_name(self): + """As the class name can interfere when reused, use the url_name""" + return self.url_name + + def get_template_names(self): + templates = ['ishtar/wizard/default_wizard.html'] + current_step = self.steps.current + if current_step == self.steps.last: + templates = ['ishtar/wizard/confirm_wizard.html'] + templates + return templates + + def get_context_data(self, form, **kwargs): + """Add previous, next and current steps to manage the wizard path""" + context = super(Wizard, self).get_context_data(form) + step = self.steps.first + current_step = self.steps.current + context.update({'current_step':self.form_list[current_step]}) + if step == current_step: + return context + previous_steps, next_steps, previous_step_counter = [], [], 0 + while step: + if step == current_step: + break + previous_steps.append(self.form_list[step]) + step = self.steps.next + previous_step_counter += 1 + context.update({'previous_steps':previous_steps, + 'previous_step_counter':previous_step_counter}) + # if modification: show the next steps + if self.modification: + next_step = step + while next_step: + # check if the form is initialized otherwise initialize it + if not storage.get_step_data(next_step): + values = self.get_form_initial(request, storage, next_step) + prefixed_values = {} + if not isinstance(values, list): + for key in values: + form_key = next_step + '-' + key + prefixed_values[form_key] = values[key] + else: + for formset_idx, v in enumerate(values): + prefix = u"-%d-" % formset_idx + for key in v: + form_key = next_step + prefix + key + prefixed_values[form_key] = v[key] + storage.set_step_data(next_step, prefixed_values) + if step != next_step: # if not current step + next_steps.append(self.form_list[next_step]) + next_step = self.get_next_step(request, storage, next_step) + context.update({'next_steps':next_steps}) + # not last step: validation + if current_step != self.steps.last: + return context + final_form_list = [] + for form_key in self.get_form_list().keys(): + form_obj = self.get_form(step=form_key, + data=self.storage.get_step_data(form_key), + files=self.storage.get_step_files(form_key)) + form_obj.is_valid() + final_form_list.append(form_obj) + last_form = final_form_list[-1] + context.update({'datas':self.get_formated_datas(final_form_list)}) + if hasattr(last_form, 'confirm_msg'): + context.update({'confirm_msg':last_form.confirm_msg}) + if hasattr(last_form, 'confirm_end_msg'): + context.update({'confirm_end_msg':last_form.confirm_end_msg}) + return context + + def get_formated_datas(self, forms): + """Get the data to present in the last page""" + datas = [] + for form in forms: + form_datas = [] + base_form = hasattr(form, 'forms') and form.forms[0] or form + associated_models = hasattr(base_form, 'associated_models') and \ + base_form.associated_models or {} + if not hasattr(form, 'cleaned_data') and hasattr(form, 'forms'): + cleaned_datas = [frm.cleaned_data for frm in form.forms + if frm.is_valid()] + if not cleaned_datas: + continue + elif not hasattr(form, 'cleaned_data'): + continue + else: + cleaned_datas = type(form.cleaned_data) == list and \ + form.cleaned_data \ + or [form.cleaned_data] + for cleaned_data in cleaned_datas: + if not cleaned_data: + continue + if form_datas: + form_datas.append(("", "", "spacer")) + items = hasattr(base_form, 'fields') and \ + base_form.fields.keyOrder or cleaned_data.keys() + for key in items: + lbl = None + if key.startswith('hidden_'): + continue + if hasattr(base_form, 'fields') and key in base_form.fields: + lbl = base_form.fields[key].label + if hasattr(base_form, 'associated_labels') \ + and key in base_form.associated_labels: + lbl = base_form.associated_labels[key] + if not lbl: + continue + value = cleaned_data[key] + if not value and value != False: + continue + if type(value) == bool: + if value == True: + value = _(u"Yes") + elif value == False: + value = _(u"No") + elif key in associated_models: + values = [] + if "," in unicode(value): + values = unicode(value).split(",") + else: + values = [value] + rendered_values = [] + for val in values: + item = associated_models[key].objects.get(pk=val) + if hasattr(item, 'short_label'): + value = item.short_label() + else: + value = unicode(item) + rendered_values.append(value) + value = u" ; ".join(rendered_values) + form_datas.append((lbl, value, '')) + if form_datas: + datas.append((form.form_label, form_datas)) + return datas + + def get_extra_model(self, dct, form_list): + dct['history_modifier'] = self.request.user + return dct + + def done(self, form_list, return_object=False, **kwargs): + """Save to the model""" + dct, m2m, whole_associated_models = {}, [], [] + for form in form_list: + if not form.is_valid(): + return self.render(form) + base_form = hasattr(form, 'forms') and form.forms[0] or form + associated_models = hasattr(base_form, 'associated_models') and \ + base_form.associated_models or {} + if hasattr(form, 'forms'): + multi = False + if form.forms: + frm = form.forms[0] + if hasattr(frm, 'base_model') and frm.base_model: + whole_associated_models.append(frm.base_model) + else: + whole_associated_models += associated_models.keys() + fields = frm.fields.copy() + if 'DELETE' in fields: + fields.pop('DELETE') + multi = len(fields) > 1 + if multi: + assert hasattr(frm, 'base_model'), \ + u"Must define a base_model for " + unicode(frm.__class__) + for frm in form.forms: + if not frm.is_valid(): + continue + vals = {} + if "DELETE" in frm.cleaned_data: + if frm.cleaned_data["DELETE"]: + continue + frm.cleaned_data.pop('DELETE') + for key in frm.cleaned_data: + value = frm.cleaned_data[key] + if not value and value != False: + continue + if key in associated_models: + value = associated_models[key].objects.get(pk=value) + if multi: + vals[key] = value + else: + m2m.append((key, value)) + if multi and vals: + m2m.append((frm.base_model, vals)) + elif type(form.cleaned_data) == dict: + for key in form.cleaned_data: + if key.startswith('hidden_'): + continue + value = form.cleaned_data[key] + if key in associated_models: + if value: + model = associated_models[key] + if isinstance(value, unicode) \ + or isinstance(value, str) and "," in value: + value = value.split(",") + if isinstance(value, list) \ + or isinstance(value, tuple): + value = [model.objects.get(pk=val) + for val in value if val] + if len(value) == 1: + value = value[0] + else: + value = model.objects.get(pk=value) + else: + value = None + dct[key] = value + return self.save_model(dct, m2m, whole_associated_models, form_list, + return_object) + + def get_saved_model(self): + """Permit a distinguo when saved model is not the base selected model""" + return self.model + + def get_current_saved_object(self): + """Permit a distinguo when saved model is not the base selected model""" + return self.get_current_object() + + def save_model(self, dct, m2m, whole_associated_models, form_list, + return_object): + dct = self.get_extra_model(dct, form_list) + obj = self.get_current_saved_object() + # manage dependant items + other_objs = {} + for k in dct.keys(): + if '__' not in k: + continue + vals = k.split('__') + assert len(vals) == 2, "Only one level of dependant item is managed" + dependant_item, key = vals + if dependant_item not in other_objs: + other_objs[dependant_item] = {} + other_objs[dependant_item][key] = dct.pop(k) + if obj: + for k in dct: + if k.startswith('pk'): + continue + setattr(obj, k, dct[k]) + try: + obj.full_clean() + except forms.ValidationError, msg: + return self.render(form_list[-1]) + for dependant_item in other_objs: + c_item = getattr(obj, dependant_item) + # manage ManyToMany if only one associated + if hasattr(c_item, "all"): + c_items = c_item.all() + if len(c_items) != 1: + continue + c_item = c_items[0] + if c_item: + # to check # + for k in other_objs[dependant_item]: + setattr(c_item, k, other_objs[dependant_item][k]) + c_item.save() + else: + m = getattr(self.model, dependant_item) + if hasattr(m, 'related'): + c_item = m.related.model(**other_objs[dependant_item]) + setattr(obj, dependant_item, c_item) + obj.save() + obj.save() + else: + adds = {} + for dependant_item in other_objs: + m = getattr(self.model, dependant_item) + model = m.field.rel.to + c_dct = other_objs[dependant_item].copy() + if issubclass(model, models.BaseHistorizedItem): + c_dct['history_modifier'] = self.request.user + c_item = model(**c_dct) + c_item.save() + if hasattr(m, 'through'): + adds[dependant_item] = c_item + elif hasattr(m, 'field'): + dct[dependant_item] = c_item + if 'pk' in dct: + dct.pop('pk') + obj = self.get_saved_model()(**dct) + try: + obj.full_clean() + except forms.ValidationError, msg: + return self.render(form_list[-1]) + obj.save() + for k in adds: + getattr(obj, k).add(adds[k]) + # necessary to manage interaction between models like + # material_index management for baseitems + obj.save() + m2m_items = {} + for model in whole_associated_models: + getattr(obj, model+'s').clear() + for key, value in m2m: + if key not in m2m_items: + if type(key) == dict: + vals = [] + for item in getattr(obj, key+'s').all(): + v = {} + for k in value.keys(): + v[k] = getattr(item, k) + vals.append(v) + m2m_items[key] = vals + else: + m2m_items[key] = getattr(obj, key+'s').all() + if value not in m2m_items[key]: + if type(value) == dict: + model = getattr(obj, key+'s').model + if issubclass(model, models.BaseHistorizedItem): + value['history_modifier'] = self.request.user + value = model.objects.create(**value) + value.save() + getattr(obj, key+'s').add(value) + # necessary to manage interaction between models like + # material_index management for baseitems + obj.save() + res = render_to_response('wizard_done.html', {}, + context_instance=RequestContext(self.request)) + return return_object and (obj, res) or res + + def get_deleted(self, keys): + """Get the deleted and non-deleted items in formsets""" + not_to_delete, to_delete = set(), set() + for key in keys: + items = key.split('-') + if len(items) < 2 or items[-2] in to_delete: + continue + idx = items[-2] + try: + int(idx) + except: + continue + if items[-1] == u'DELETE': + to_delete.add(idx) + if idx in not_to_delete: + not_to_delete.remove(idx) + elif idx not in not_to_delete: + not_to_delete.add(idx) + return (to_delete, not_to_delete) + + def get_form(self, step=None, data=None, files=None): + """Manage formset""" + request = self.request + storage = self.storage + if data: + data = data.copy() + if not step: + step = self.steps.current + form = self.get_form_list()[step] + if hasattr(form, 'management_form'): + # manage deletion + to_delete, not_to_delete = self.get_deleted(data.keys()) + # raz deleted fields + for key in data.keys(): + items = key.split('-') + if len(items) < 2 or items[-2] not in to_delete: + continue + data.pop(key) + if to_delete: + # reorganize + for idx, number in enumerate(sorted(not_to_delete)): + idx = unicode(idx) + if idx == number: + continue + for key in data.keys(): + items = key.split('-') + if len(items) > 2 and number == items[-2]: + items[-2] = unicode(idx) + k = u'-'.join(items) + data[k] = data.pop(key)[0] + # get a form key + base_key = form.form.base_fields.keys()[0] + init = self.get_form_initial(request, storage, step) + total_field = len([key for key in data.keys() + if base_key in key.split('-') + and data[key]]) + if init and not to_delete: + total_field = max((total_field, len(init))) + data[step + u'-INITIAL_FORMS'] = unicode(total_field) + data[step + u'-TOTAL_FORMS'] = unicode(total_field + 1) + data = data or None + form = super(Wizard, self).get_form(step, data, files) + return form + + def render_next_step(self, form, **kwargs): + """ + Manage: + - modify or delete button in formset: next step = current step + - validate and end: nextstep = last step + """ + request = self.request + if request.POST.has_key('formset_modify') \ + and request.POST['formset_modify'] \ + or [key for key in request.POST.keys() + if key.endswith('DELETE') and request.POST[key]]: + return self.render(form) + elif request.POST.has_key('validate_and_end') \ + and request.POST['validate_and_end']: + last_step = self.steps.last + new_form = self.get_form(last_step, + data=self.storage.get_step_data(last_step), + files=self.storage.get_step_files(last_step)) + self.storage.current_step = last_step + return self.render(new_form) + return super(Wizard, self).render_next_step(form, **kwargs) + + def post(self, *args, **kwargs): + """Convert numerical step number to step name""" + request = self.request + post_data = request.POST.copy() + if request.POST.has_key('form_prev_step'): + try: + step_number = int(request.POST['form_prev_step']) + post_data['wizard_goto_step'] = self.get_form_list().keys( + )[step_number] + except ValueError: + pass + request.POST = post_data + return super(Wizard, self).post(*args, **kwargs) + + @classmethod + def session_has_key(cls, request, storage, form_key, key=None, multi=None): + """Check if the session has value of a specific form and (if provided) + of a key + """ + test = storage.prefix in request.session \ + and 'step_data' in request.session[storage.prefix] \ + and form_key in request.session[storage.prefix]['step_data'] + if not key or not test: + return test + key = key.startswith(form_key) and key or \ + not multi and form_key + '-' + key or \ + form_key + '-0-' + key #only check if the first field is available + return key in request.session[storage.prefix]['step_data'][form_key] + + @classmethod + def session_get_value(cls, request, storage, form_key, key, multi=False): + """Get the value of a specific form""" + if not cls.session_has_key(request, storage, form_key, key, multi): + return + if not multi: + key = key.startswith(form_key) and key or form_key + '-' + key + return request.session[storage.prefix]['step_data'][form_key][key] + vals = [] + for k in request.session[storage.prefix]['step_data'][form_key]: + if k.startswith(form_key) and k.endswith(key) and \ + request.session[storage.prefix]['step_data'][form_key][k]: + vals.append(request.session[storage.prefix]['step_data']\ + [form_key][k]) + return vals + + def get_current_object(self): + """Get the current object for an instancied wizard""" + current_obj = None + main_form_key = 'selec-' + self.url_name + try: + idx = int(self.session_get_value(self.request, self.storage, + main_form_key, 'pk')) + current_obj = self.model.objects.get(pk=idx) + except(TypeError, ValueError, ObjectDoesNotExist): + pass + return current_obj + + def get_form_initial(self, step): + current_obj = self.get_current_object() + current_step = self.steps.current + if step.startswith('selec-') and step in self.form_list \ + and 'pk' in self.form_list[step].associated_models: + model_name = self.form_list[step].associated_models['pk' + ].__name__.lower() + if step == current_step: + self.reset_wizard(request, storage) + val = model_name in request.session and request.session[model_name] + if val: + return {'pk':val} + elif current_obj: + return self.get_instanced_init(current_obj, step) + current_form = self.form_list[current_step] + if hasattr(current_form, 'currents'): + initial = {} + for key in current_form.currents: + model_name = current_form.currents[key].__name__.lower() + val = model_name in request.session and \ + request.session[model_name] + if val: + initial[key] = val + if initial: + return initial + return super(Wizard, self).get_form_initial(step) + + def get_instanced_init(self, obj, step=None): + """Get initial data from an init""" + current_step = step or self.steps.current + c_form = self.form_list[current_step] + # make the current object the default item for the session + obj_name = obj.__class__.__name__.lower() + # prefer a specialized name if available + prefixes = self.storage.prefix.split('_') + if len(prefixes) > 1 and prefixes[-2].startswith(obj_name): + obj_name = prefixes[-2] + self.request.session[obj_name] = unicode(obj.pk) + initial = {} + if self.request.POST or \ + (step in self.request.session[self.storage.prefix] and\ + self.request.session[self.storage.prefix]['step_data'][step]): + return {} + if hasattr(c_form, 'base_fields'): + for base_field in c_form.base_fields.keys(): + fields = base_field.split('__') + value = obj + for field in fields: + if not hasattr(value, field) or \ + getattr(value, field) == None: + value = obj + break + value = getattr(value, field) + if value == obj: + continue + if hasattr(value, 'pk'): + value = value.pk + if value in (True, False): + initial[base_field] = value + elif value != None: + initial[base_field] = unicode(value) + elif hasattr(c_form, 'management_form'): + initial = [] + if hasattr(c_form.form, 'base_model'): + key = c_form.form.base_model + 's' + else: + key = current_step.split('-')[0] + if not hasattr(obj, key): + return initial + keys = c_form.form.base_fields.keys() + for child_obj in getattr(obj, key).order_by('pk').all(): + if not keys: + break + vals = {} + if len(keys) == 1: + # only one field: must be the id of the object + vals[keys[0]] = unicode(child_obj.pk) + else: + for field in keys: + if hasattr(child_obj, field): + value = getattr(child_obj, field) + if hasattr(value, 'pk'): + value = value.pk + if value != None: + vals[field] = unicode(value) + if vals: + initial.append(vals) + return initial + +class PersonWizard(Wizard): + model = models.Person + +person_creation_wizard = PersonWizard.as_view([ + ('identity-person_creation', PersonForm), + ('final-person_creation', FinalForm)], + url_name='person_creation_step',) + + +def update_current_item(request): + if not request.is_ajax() and not request.method == 'POST': + raise Http404 + if 'value' in request.POST and 'item' in request.POST: + request.session[request.POST['item']] = request.POST['value'] + return HttpResponse('ok') + +def check_permission(request, action_slug, obj_id=None): + if action_slug not in menu.items: + #! TODO + return True + if obj_id: + return menu.items[action_slug].is_available(request.user, obj_id) + return menu.items[action_slug].can_be_available(request.user) + +def autocomplete_person(request, person_type=None): + person_types = request.user.ishtaruser.person.person_type + if (not request.user.has_perm('ishtar_common.view_person', models.Person) and + not request.user.has_perm('ishtar_common.view_own_person', models.Person) + and not person_types.rights.filter(wizard__url_name='person_search' + ).count()): + return HttpResponse(mimetype='text/plain') + if not request.GET.get('term'): + return HttpResponse(mimetype='text/plain') + q = request.GET.get('term') + limit = request.GET.get('limit', 20) + try: + limit = int(limit) + except ValueError: + return HttpResponseBadRequest() + query = Q() + for q in q.split(' '): + query = query & (Q(name__icontains=q) | Q(surname__icontains=q) | \ + Q(email__icontains=q)) + if person_type: + try: + typs = [int(tp) for tp in person_type.split('_') if tp] + typ = models.PersonType.objects.filter(pk__in=typs).all() + query = query & Q(person_type__in=typ) + except (ValueError, ObjectDoesNotExist): + pass + limit = 20 + persons = models.Person.objects.filter(query)[:limit] + data = json.dumps([{'id':person.pk, 'value':unicode(person)} + for person in persons if person]) + return HttpResponse(data, mimetype='text/plain') + +def autocomplete_town(request): + if not request.GET.get('term'): + return HttpResponse(mimetype='text/plain') + q = request.GET.get('term') + query = Q() + for q in q.split(' '): + extra = Q(name__icontains=q) + if settings.COUNTRY == 'fr': + extra = (extra | Q(numero_insee__istartswith=q) | \ + Q(departement__label__istartswith=q)) + query = query & extra + limit = 20 + towns = models.Town.objects.filter(query)[:limit] + data = json.dumps([{'id':town.pk, 'value':unicode(town)} + for town in towns]) + return HttpResponse(data, mimetype='text/plain') + +def autocomplete_file(request): + person_types = request.user.ishtaruser.person.person_type + if (not request.user.has_perm('ishtar_common.view_file', models.File) and \ + not request.user.has_perm('ishtar_common.view_own_file', models.File) + and not person_types.rights.filter(wizard__url_name='file_search' + ).count()): + return HttpResponse(mimetype='text/plain') + if not request.GET.get('term'): + return HttpResponse(mimetype='text/plain') + q = request.GET.get('term') + query = Q() + for q in q.split(' '): + extra = Q(internal_reference__icontains=q) | \ + Q(towns__name__icontains=q) + try: + value = int(q) + extra = extra | Q(year=q) | Q(numeric_reference=q) + except ValueError: + pass + query = query & extra + limit = 20 + files = models.File.objects.filter(query)[:limit] + data = json.dumps([{'id':file.pk, 'value':unicode(file)} + for file in files]) + return HttpResponse(data, mimetype='text/plain') + +from types import NoneType + +def format_val(val): + if type(val) == NoneType: + return u"" + if type(val) == bool: + if val: + return unicode(_(u"True")) + else: + return unicode(_(u"False")) + return unicode(val) + +HIERARCHIC_LEVELS = 5 +HIERARCHIC_FIELDS = ['period', 'unit', 'material_type'] +PRIVATE_FIELDS = ('id', 'history_modifier', 'order') +def get_item(model, func_name, default_name, extra_request_keys=[], + base_request={}, bool_fields=[]): + """ + Generic treatment of tables + """ + def func(request, data_type='json', full=False, **dct): + if 'type' in dct: + data_type = dct.pop('type') + if not data_type: + data_type = 'json' + fields = [model._meta.get_field_by_name(k)[0] + for k in model._meta.get_all_field_names()] + request_keys = dict([(field.name, + field.name + (hasattr(field, 'rel') and field.rel and '__pk' or '')) + for field in fields]) + request_keys.update(extra_request_keys) + request_items = request.method == 'POST' and request.POST or request.GET + dct = base_request.copy() + try: + old = 'old' in request_items and int(request_items['old']) + except ValueError: + return HttpResponse(None, mimetype='text/plain') + for k in request_keys: + q = request_items.get(k) + if not q: + continue + dct[request_keys[k]] = q + if not dct and 'submited' not in request_items: + if default_name in request.session and \ + request.session[default_name]: + dct = {"pk":request.session[default_name]} + if (not dct or data_type == 'csv') and func_name in request.session: + dct = request.session[func_name] + else: + request.session[func_name] = dct + for k in bool_fields: + if k in dct: + if dct[k] == u"1": + dct.pop(k) + else: + dct[k] = dct[k] == u"2" and True or False + + # manage hierarchic conditions + or_reqs = [] + for req in dct.copy(): + for k_hr in HIERARCHIC_FIELDS: + if req.endswith(k_hr + '__pk'): + val = dct.pop(req) + reqs = Q(**{req:val}) + req = req[:-2] + '__' + for idx in xrange(HIERARCHIC_LEVELS): + req = req[:-2] + 'parent__pk' + q = Q(**{req:val}) + reqs = reqs | q + or_reqs.append(reqs) + break + query = Q(**dct) + for or_req in or_reqs: + query = query & or_req + items = model.objects.filter(query) + q = request_items.get('sidx') + + # manage sort tables + if q and q in request_keys: + ks = request_keys[q] + if type(ks) not in (list, tuple): + ks = [ks] + orders = [] + for k in ks: + if k.endswith("__pk"): + k = k[:-len("__pk")] + "__label" + q = request_items.get('sord') + sign = q and q == u'desc' and "-" or '' + if '__' in k: + k = k.split('__')[0] + orders.append(sign+k) + items = items.order_by(*orders) + + # pager management + start, end = 0, None + page_nb = 1 + try: + row_nb = int(request_items.get('rows')) + except (ValueError, TypeError): + row_nb = None + if row_nb: + try: + page_nb = int(request_items.get('page')) + assert page_nb >= 1 + except (ValueError, AssertionError): + pass + start = (page_nb-1)*row_nb + end = page_nb*row_nb + items_nb = items.count() + items = items[start:end] + + datas = [] + if old: + items = [item.get_previous(old) for item in items] + table_cols = full and [field.name for field in model._meta.fields + if field.name not in PRIVATE_FIELDS] \ + or model.TABLE_COLS + for item in items: + data = [item.pk] + for k in table_cols: + vals = [item] + for ky in k.split('.'): + new_vals = [] + for val in vals: + if hasattr(val, 'all'): # manage related objects + val = list(val.all()) + for v in val: + new_vals.append(getattr(v, ky)) + elif val: + new_vals.append(getattr(val, ky)) + vals = new_vals + if vals and hasattr(vals[0], 'all'): # manage last related objects + new_vals = [] + for val in vals: + new_vals += list(val.all()) + vals = new_vals + data.append(", ".join([format_val(v) for v in vals]) or u"") + datas.append(data) + link_template = "<a href='#' onclick='load_window(\"%%s\")'>%s</a>" % \ + (unicode(_("Details"))) + if data_type == "json": + rows = [] + for data in datas: + try: + lnk = link_template % reverse('show-'+default_name, + args=[data[0], '']) + except NoReverseMatch: + lnk = '' + res = {'id':data[0], 'link':lnk} + for idx, value in enumerate(data[1:]): + if value: + res[table_cols[idx].split('.')[-1]] = value + rows.append(res) + data = json.dumps({ + "records":items_nb, + "rows":rows, + "page":page_nb, + "total":items_nb/row_nb + 1, + }) + return HttpResponse(data, mimetype='text/plain') + elif data_type == "csv": + response = HttpResponse(mimetype='text/csv') + n = datetime.datetime.now() + filename = u'%s_%s.csv' % (default_name, + n.strftime('%Y%m%d-%H%M%S')) + response['Content-Disposition'] = 'attachment; filename=%s'%filename + writer = csv.writer(response, **CSV_OPTIONS) + col_names = [] + for field_name in table_cols: + try: + field = model._meta.get_field(field_name) + except: + col_names.append(u"".encode(ENCODING)) + continue + col_names.append(unicode(field.verbose_name).encode(ENCODING)) + writer.writerow(col_names) + for data in datas: + writer.writerow([val.encode(ENCODING) for val in data[1:]]) + return response + return HttpResponse(None, mimetype='text/plain') + + return func + +def show_item(model, name): + def func(request, pk, **dct): + try: + item = model.objects.get(pk=pk) + except ObjectDoesNotExist: + return HttpResponse(None) + doc_type = 'type' in dct and dct.pop('type') + date = 'date' in dct and dct.pop('date') + dct['window_id'] = "%s-%d-%s" % (name, item.pk, + datetime.datetime.now().strftime('%M%s')) + if date: + try: + date = datetime.datetime.strptime(date, '%Y-%m-%dT%H:%M:%S.%f') + item = item.get_previous(date=date) + assert item != None + except (ValueError, AssertionError): + return HttpResponse(None, mimetype='text/plain') + dct['previous'] = item._previous + dct['next'] = item._next + else: + historized = item.history.all() + if historized: + item.history_date = historized[0].history_date + if len(historized) > 1: + dct['previous'] = historized[1].history_date + dct['item'], dct['item_name'] = item, name + context_instance = RequestContext(request) + context_instance.update(dct) + n = datetime.datetime.now() + filename = u'%s_%s_%s' % (name, slugify(unicode(item)), + n.strftime('%Y%m%d-%H%M%S')) + if doc_type == "odt" and settings.XHTML2ODT_PATH and \ + settings.ODT_TEMPLATE: + tpl = loader.get_template('sheet_%s.html' % name) + content = tpl.render(context_instance) + try: + tidy_options = dict(output_xhtml=1, add_xml_decl=1, indent=1, + tidy_mark=0, output_encoding='utf8', doctype='auto', + wrap=0, char_encoding='utf8') + html = str(tidy.parseString(content.encode('utf-8'), + **tidy_options)) + html = html.replace(" ", " ") + html = re.sub('<pre([^>]*)>\n', '<pre\\1>', html) + + odt = NamedTemporaryFile() + options = optparse.Values() + options.with_network = True + for k, v in (('input', ''), + ('output', odt.name), + ('template', settings.ODT_TEMPLATE), + ('with_network', True), + ('top_header_level', 1), + ('img_width', '8cm'), + ('img_height', '6cm'), + ('verbose', False), + ('replace_keyword', 'ODT-INSERT'), + ('cut_start', 'ODT-CUT-START'), + ('htmlid', None), + ('url', "#")): + setattr(options, k, v) + odtfile = xhtml2odt.ODTFile(options) + odtfile.open() + odtfile.import_xhtml(html) + odtfile = odtfile.save() + except xhtml2odt.ODTExportError, ex: + return HttpResponse(content, content_type="application/xhtml") + response = HttpResponse( + mimetype='application/vnd.oasis.opendocument.text') + response['Content-Disposition'] = 'attachment; filename=%s.odt' % \ + filename + response.write(odtfile) + return response + elif doc_type == 'pdf': + tpl = loader.get_template('sheet_%s_pdf.html' % name) + content = tpl.render(context_instance) + result = StringIO.StringIO() + html = content.encode('utf-8') + html = html.replace("<table", "<pdf:nextpage/><table repeat='1'") + pdf = pisa.pisaDocument(StringIO.StringIO(html), result) + response = HttpResponse(result.getvalue(), + mimetype='application/pdf') + response['Content-Disposition'] = 'attachment; filename=%s.pdf' % \ + filename + if not pdf.err: + return response + return HttpResponse(content, content_type="application/xhtml") + else: + tpl = loader.get_template('sheet_%s_window.html' % name) + content = tpl.render(context_instance) + return HttpResponse(content, content_type="application/xhtml") + return func + +def revert_item(model): + def func(request, pk, date, **dct): + try: + item = model.objects.get(pk=pk) + date = datetime.datetime.strptime(date, '%Y-%m-%dT%H:%M:%S.%f') + item.rollback(date) + except (ObjectDoesNotExist, ValueError, HistoryError): + return HttpResponse(None, mimetype='text/plain') + return HttpResponse("True", mimetype='text/plain') + return func + + +get_file = get_item(models.File, 'get_file', 'file') +show_file = show_item(models.File, 'file') +revert_file = revert_item(models.File) + +def autocomplete_operation(request, non_closed=True): + person_types = request.user.ishtaruser.person.person_type + if (not request.user.has_perm('ishtar_common.view_operation', models.Operation)\ + and not request.user.has_perm('ishtar_common.view_own_operation', + models.Operation) + and not person_types.rights.filter(wizard__url_name='operation_search' + ).count()): + return HttpResponse(mimetype='text/plain') + if not request.GET.get('term'): + return HttpResponse(mimetype='text/plain') + q = request.GET.get('term') + query = Q() + for q in q.split(' '): + extra = Q(towns__name__icontains=q) + try: + value = int(q) + extra = extra | Q(year=q) | Q(operation_code=q) + except ValueError: + pass + query = query & extra + if non_closed: + query = query & Q(end_date__isnull=True) + limit = 15 + operations = models.Operation.objects.filter(query)[:limit] + data = json.dumps([{'id':operation.pk, 'value':unicode(operation)} + for operation in operations]) + return HttpResponse(data, mimetype='text/plain') + +def get_available_operation_code(request, year=None): + if not request.user.has_perm('ishtar_common.view_operation', models.Operation)\ + and not request.user.has_perm('ishtar_common.view_own_operation', + models.Operation): + return HttpResponse(mimetype='text/plain') + data = json.dumps({'id':models.Operation.get_available_operation_code(year)}) + return HttpResponse(data, mimetype='text/plain') + +get_operation = get_item(models.Operation, 'get_operation', 'operation', + bool_fields = ['end_date__isnull'], + extra_request_keys={'common_name':'common_name__icontains', + 'end_date':'end_date__isnull', + 'year_index':('year', 'operation_code')}) +show_operation = show_item(models.Operation, 'operation') +revert_operation = revert_item(models.Operation) + +get_operationsource = get_item(models.OperationSource, + 'get_operationsource', 'operationsource', + extra_request_keys={'operation__towns':'operation__towns__pk', + 'operation__operation_type':'operation__operation_type__pk', + 'operation__year':'operation__year'}) + +get_administrativeactfile = get_item(models.AdministrativeAct, + 'get_administrativeactfile', 'administrativeactfile', + extra_request_keys={'associated_file__towns':'associated_file__towns__pk', + 'operation__towns':'operation__towns__pk', + 'act_type__intented_to':'act_type__intented_to'}) +get_administrativeactop = get_item(models.AdministrativeAct, + 'get_administrativeactop', 'administrativeactop', + extra_request_keys={'associated_file__towns':'associated_file__towns__pk', + 'operation__towns':'operation__towns__pk', + 'act_type__intented_to':'act_type__intented_to'}) + +def autocomplete_organization(request, orga_type=None): + person_types = request.user.ishtaruser.person.person_type + if (not request.user.has_perm('ishtar_common.view_organization', + models.Organization) and \ + not request.user.has_perm('ishtar_common.view_own_organization', + models.Organization) + and not person_types.rights.filter(wizard__url_name='person_search' + ).count()): + return HttpResponse(mimetype='text/plain') + if not request.GET.get('term'): + return HttpResponse(mimetype='text/plain') + q = request.GET.get('term') + query = Q() + for q in q.split(' '): + extra = Q(name__icontains=q) + query = query & extra + if orga_type: + try: + typs = [int(tp) for tp in orga_type.split('_') if tp] + typ = models.OrganizationType.objects.filter(pk__in=typs).all() + query = query & Q(organization_type__in=typ) + except (ValueError, ObjectDoesNotExist): + pass + limit = 15 + organizations = models.Organization.objects.filter(query)[:limit] + data = json.dumps([{'id':org.pk, 'value':unicode(org)} + for org in organizations]) + return HttpResponse(data, mimetype='text/plain') + +show_contextrecord = show_item(models.ContextRecord, 'contextrecord') +get_contextrecord = get_item(models.ContextRecord, + 'get_contextrecord', 'contextrecord', + extra_request_keys={'parcel__town':'parcel__town__pk', + 'operation__year':'operation__year__contains', + 'datings__period':'datings__period__pk'},) +get_contextrecordsource = get_item(models.ContextRecordSource, + 'get_contextrecordsource', 'contextrecordsource', + extra_request_keys={ + 'context_record__parcel__town':'context_record__parcel__town__pk', + 'context_record__operation__year':'context_record__operation__year', + 'context_record__datings__period':'context_record__datings__period__pk', + 'context_record__unit':'context_record__unit__pk', + }) +get_archaeologicalitem = get_item(models.Item, + 'get_archaeologicalitem', 'item', + bool_fields = ['base_items__is_isolated'], + base_request={'downstream_treatment__isnull':True}, + extra_request_keys={ +'base_items__context_record__parcel__town': + 'base_items__context_record__parcel__town', +'base_items__context_record__operation__year': + 'base_items__context_record__operation__year__contains', +'base_items__context_record__operation__code_patriarche': + 'base_items__context_record__operation__code_patriarche', +'dating__period':'dating__period__pk', +'base_items__item__description':'base_items__item__description__icontains', +'base_items__is_isolated':'base_items__is_isolated'}) +get_itemsource = get_item(models.ItemSource, + 'get_itemsource', 'itemsource', + extra_request_keys={ +'item__context_record__operation__year':'item__context_record__operation__year', +'item__dating__period':'item__dating__period__pk', +'item__description':'item__description__icontains', + }) +get_container = get_item(models.Container, + 'get_container', 'container', + extra_request_keys={ +'location':'location__pk', +'container_type':'container_type__pk', +'reference':'reference__icontains', + }) + +def autocomplete_warehouse(request): + if not request.user.has_perm('ishtar_common.view_warehouse', models.Warehouse)\ + and not request.user.has_perm('ishtar_common.view_own_warehouse', + models.Warehouse) : + return HttpResponse(mimetype='text/plain') + if not request.GET.get('term'): + return HttpResponse(mimetype='text/plain') + q = request.GET.get('term') + query = Q() + for q in q.split(' '): + extra = Q(name__icontains=q) | \ + Q(warehouse_type__label__icontains=q) + query = query & extra + limit = 15 + warehouses = models.Warehouse.objects.filter(query)[:limit] + data = json.dumps([{'id':warehouse.pk, 'value':unicode(warehouse)} + for warehouse in warehouses]) + return HttpResponse(data, mimetype='text/plain') + +def autocomplete_author(request): + if not request.user.has_perm('ishtar_common.view_author', models.Author)\ + and not request.user.has_perm('ishtar_common.view_own_author', + models.Warehouse) : + return HttpResponse(mimetype='text/plain') + if not request.GET.get('term'): + return HttpResponse(mimetype='text/plain') + q = request.GET.get('term') + query = Q() + for q in q.split(' '): + extra = Q(person__name__icontains=q) | \ + Q(person__surname__icontains=q) | \ + Q(person__email__icontains=q) | \ + Q(author_type__label__icontains=q) + query = query & extra + limit = 15 + authors = models.Author.objects.filter(query)[:limit] + data = json.dumps([{'id':author.pk, 'value':unicode(author)} + for author in authors]) + return HttpResponse(data, mimetype='text/plain') + +def autocomplete_container(request): + if not request.user.has_perm('ishtar_common.view_warehouse', + models.Warehouse)\ + and not request.user.has_perm('ishtar_common.view_own_warehouse', + models.Warehouse): + return HttpResponse(mimetype='text/plain') + if not request.GET.get('term'): + return HttpResponse(mimetype='text/plain') + q = request.GET.get('term') + query = Q() + for q in q.split(' '): + extra = Q(container_type__label__icontains=q) | \ + Q(container_type__reference__icontains=q) | \ + Q(reference__icontains=q) | \ + Q(location__name=q) | \ + Q(location__town=q) + query = query & extra + limit = 15 + containers = models.Container.objects.filter(query)[:limit] + data = json.dumps([{'id':container.pk, 'value':unicode(container)} + for container in containers]) + return HttpResponse(data, mimetype='text/plain') + +def new_item(model): + def func(request, parent_name): + model_name = model._meta.object_name + if not check_permission(request, 'add_'+model_name.lower()): + not_permitted_msg = ugettext(u"Operation not permitted.") + return HttpResponse(not_permitted_msg) + frm = getattr(ishtar_forms, model_name + 'Form') + dct = {'title':unicode(_(u'New %s' % model_name.lower()))} + if request.method == 'POST': + dct['form'] = frm(request.POST) + if dct['form'].is_valid(): + new_item = dct['form'].save(request.user) + dct['new_item_label'] = unicode(new_item) + dct['new_item_pk'] = new_item.pk + dct['parent_name'] = parent_name + dct['parent_pk'] = parent_name + if dct['parent_pk'] and '_select_' in dct['parent_pk']: + parents = dct['parent_pk'].split('_') + dct['parent_pk'] = "_".join([parents[0]] + parents[2:]) + return render_to_response('window.html', dct, + context_instance=RequestContext(request)) + else: + dct['form'] = frm() + return render_to_response('window.html', dct, + context_instance=RequestContext(request)) + return func + +new_warehouse = new_item(models.Warehouse) +new_person = new_item(models.Person) +new_organization = new_item(models.Organization) +new_author = new_item(models.Author) +new_container = new_item(models.Container) + +def action(request, action_slug, obj_id=None, *args, **kwargs): + """ + Action management + """ + if not check_permission(request, action_slug, obj_id): + not_permitted_msg = ugettext(u"Operation not permitted.") + return HttpResponse(not_permitted_msg) + request.session['CURRENT_ACTION'] = action_slug + associated_wizard = action_slug + '_wizard' + dct = {} + globals_dct = globals() + if action_slug in globals_dct: + return globals_dct[action_slug](request, dct, obj_id, *args, **kwargs) + elif hasattr(ishtar_forms, action_slug + "_wizard"): + return getattr(ishtar_forms, action_slug+"_wizard")(request, *args, + **kwargs) + return render_to_response('index.html', dct, + context_instance=RequestContext(request)) + +def dashboard_main(request, dct, obj_id=None, *args, **kwargs): + """ + Main dashboard + """ + dct = {'items':[ + (_(u"Archaeological files"), models.Dashboard(models.File)), + (_(u"Operations"), models.Dashboard(models.Operation)), + (_(u"Context records"), models.Dashboard(models.ContextRecord)), + (_(u"Archaeological items"), models.Dashboard(models.Item)), + ], + 'ishtar_users':models.UserDashboard()} + return render_to_response('dashboard_main.html', dct, + context_instance=RequestContext(request)) + +def dashboard_file(request, dct, obj_id=None, *args, **kwargs): + """ + Main dashboard + """ + dct = {'dashboard': models.FileDashboard()} + return render_to_response('dashboard_file.html', dct, + context_instance=RequestContext(request)) + +def dashboard_operation(request, dct, obj_id=None, *args, **kwargs): + """ + Operation dashboard + """ + dct = {'dashboard': models.OperationDashboard()} + return render_to_response('dashboard_operation.html', dct, + context_instance=RequestContext(request)) diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py new file mode 100644 index 000000000..ecc48a1e8 --- /dev/null +++ b/ishtar_common/widgets.py @@ -0,0 +1,368 @@ +#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# Copyright (C) 2010-2011 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
+# Copyright (C) 2007 skam <massimo dot scamarcia at gmail.com>
+# (http://djangosnippets.org/snippets/233/)
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details.
+
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# See the file COPYING for details.
+
+from django import forms
+from django.conf import settings
+from django.core.urlresolvers import resolve, reverse
+from django.db.models import fields
+from django.forms.widgets import flatatt
+from django.template import Context, loader
+from django.utils.encoding import smart_unicode
+from django.utils.html import escape
+from django.utils.safestring import mark_safe
+from django.utils.simplejson import JSONEncoder
+from django.utils.translation import ugettext_lazy as _
+
+import models
+
+class DeleteWidget(forms.CheckboxInput):
+ def render(self, name, value, attrs=None):
+ final_attrs = flatatt(self.build_attrs(attrs, name=name,
+ value='1'))
+ output = ['<tr class="delete"><td colspan="2">']
+ output.append(u"<button%s>%s</button>" % (final_attrs, _("Delete")))
+ output.append('</td></tr>')
+ return mark_safe('\n'.join(output))
+
+class SquareMeterWidget(forms.TextInput):
+ def render(self, name, value, attrs=None):
+ if not value:
+ value = u""
+ final_attrs = flatatt(self.build_attrs(attrs, name=name, value=value))
+ output = u'<input class="area_widget" type="text"%s> %s '\
+ u'(<span id="ha_%s">0</span> ha)' % (final_attrs,
+ settings.SURFACE_UNIT_LABEL, attrs['id'])
+ output += """
+<script type="text/javascript"><!--//
+ function evaluate_%(safe_id)s(){
+ value = parseFloat($("#%(id)s").val());
+ if(!isNaN(value)){
+ value = value/10000;
+ } else {
+ value = 0;
+ }
+ $("#ha_%(id)s").html(value);
+ }
+ $("#%(id)s").keyup(evaluate_%(safe_id)s);
+ $(document).ready(evaluate_%(safe_id)s());
+//--></script>
+""" % {"id":attrs['id'], "safe_id":attrs['id'].replace('-', '_')}
+ return mark_safe(output)
+
+AreaWidget = forms.TextInput
+if settings.SURFACE_UNIT == 'square-metre':
+ global AreaWidget
+ AreaWidget = SquareMeterWidget
+
+class JQueryDate(forms.TextInput):
+ def __init__(self, *args, **kwargs):
+ super(JQueryDate, self).__init__(*args, **kwargs)
+ if 'class' not in self.attrs:
+ self.attrs['class'] = ''
+ self.attrs['class'] = 'date-pickup'
+
+ def render(self, name, value=None, attrs=None):
+ rendered = super(JQueryDate, self).render(name, value, attrs)
+ # use window.onload to be sure that datepicker don't interfere
+ # with autocomplete fields
+ rendered += """
+<script type="text/javascript"><!--//
+ $(window).load(function() {
+ $(".date-pickup").datepicker($.datepicker.regional["%(country)s"]);
+ var val = $("#id_%(name)s").val();
+ if(val){
+ var dt = $.datepicker.parseDate('yy-mm-dd', val);
+ val = $.datepicker.formatDate(
+ $.datepicker.regional["%(country)s"]['dateFormat'],
+ dt);
+ $("#id_%(name)s").val(val);
+ }
+ });
+//--></script>
+""" % {"name":name, "country":settings.COUNTRY}
+ return rendered
+
+class JQueryAutoComplete(forms.TextInput):
+ def __init__(self, source, associated_model=None, options={}, attrs={},
+ new=False):
+ """
+ Source can be a list containing the autocomplete values or a
+ string containing the url used for the request.
+ """
+ self.options = None
+ self.attrs = {}
+ self.source = source
+ self.associated_model = associated_model
+ if len(options) > 0:
+ self.options = JSONEncoder().encode(options)
+ self.attrs.update(attrs)
+ self.new = new
+
+ def render_js(self, field_id):
+ if isinstance(self.source, list):
+ source = JSONEncoder().encode(self.source)
+ elif isinstance(self.source, str) or isinstance(self.source, unicode):
+ source = "'%s'" % escape(self.source)
+ else:
+ try:
+ source = "'" + unicode(self.source) + "'"
+ except:
+ raise ValueError('source type is not valid')
+ options = 'source : ' + source
+ options += ''', select: function( event, ui ) {
+ if(ui.item){
+ $('#id_%s').val(ui.item.id);
+ } else {
+ $('#id_%s').val(null);
+ }
+ }, minLength: 2
+ ''' % (field_id, field_id)
+ if self.options:
+ options += ',%s' % self.options
+
+ js = u'$(\'#id_select_%s\').autocomplete({%s});\n' % (field_id, options)
+ js += u'''$(\'#id_select_%s\').live('click', function(){
+ $('#id_%s').val(null);
+ $('#id_select_%s').val(null);
+});''' % (field_id, field_id, field_id)
+ return js
+
+ def render(self, name, value=None, attrs=None):
+ attrs_hidden = self.build_attrs(attrs, name=name)
+ attrs_select = self.build_attrs(attrs)
+
+ if value:
+ val = escape(smart_unicode(value))
+ attrs_hidden['value'] = val
+ attrs_select['value'] = val
+ if self.associated_model:
+ try:
+ attrs_select['value'] = unicode(self.associated_model.\
+objects.get(pk=value))
+ except:
+ attrs_select['value'] = ""
+ 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'
+ new = ''
+ if self.new:
+ model_name = self.associated_model._meta.object_name.lower()
+ url_new = reverse('new-' + model_name, args=[attrs_select['id']])
+ new = u' <a href="#" class="add-button" '\
+ u'onclick="open_window(\'%s\');">+</a>' % url_new
+ html = u'''<input%(attrs_select)s/>%(new)s\
+<input type="hidden"%(attrs_hidden)s/>\
+ <script type="text/javascript"><!--//
+ $(function() {%(js)s});//--></script>
+ ''' % {
+ 'attrs_select' : flatatt(attrs_select),
+ 'attrs_hidden' : flatatt(attrs_hidden),
+ 'js' : self.render_js(name),
+ 'new':new
+ }
+ return html
+
+class JQueryJqGrid(forms.RadioSelect):
+ COL_TPL = "{name:'%(idx)s', index:'%(idx)s', sortable:true}"
+ class Media:
+ js = ['%s/js/i18n/grid.locale-%s.js' % (settings.MEDIA_URL,
+ settings.COUNTRY),
+ '%s/js/jquery.jqGrid.min.js' % settings.MEDIA_URL,
+ ]
+ css = {'all':['%s/media/ui.jqgrid.css' % settings.MEDIA_URL,
+ ]}
+
+ def __init__(self, source, form, associated_model, attrs={},
+ table_cols='TABLE_COLS', multiple=False, multiple_cols=[2], new=False,
+ new_message="", source_full=None):
+ self.source = source
+ self.form = form
+ self.attrs = attrs
+ self.associated_model = associated_model
+ self.table_cols = table_cols
+ self.multiple = multiple
+ self.multiple_cols = multiple_cols
+ self.new, self.new_message = new, new_message
+ self.source_full = source_full
+
+ def render(self, name, value=None, attrs=None):
+ t = loader.get_template('form_snippet.html')
+ rendered = t.render(Context({'form':self.form}))
+ rendered += u"\n</table>\n"\
+ u"<button id='search_%s' class='submit'>%s</button>" % (
+ name, unicode(_("Search")))
+ if self.new:
+ model_name = self.associated_model._meta.object_name.lower()
+ url_new = reverse('new-' + model_name)
+ rendered += u'<p><a href="#" onclick="open_window(\'%s\');">'\
+ u'%s</a></p>' % (url_new, unicode(self.new_message))
+ rendered += "\n<h4>%s</h4>\n" % unicode(_("Search and select an item"))
+ extra_cols = []
+ col_names, col_idx = [], []
+ for k in self.form.fields:
+ field = self.form.fields[k]
+ col_idx.append(u'"%s"' % k)
+ for field_name in getattr(self.associated_model, self.table_cols):
+ field = self.associated_model
+ keys = field_name.split('.')
+ field_verbose_name = ""
+ for key in keys:
+ if hasattr(field, 'rel'):
+ field = field.rel.to
+ try:
+ field = field._meta.get_field(key)
+ field_verbose_name = field.verbose_name
+ field_name = field.name
+ except fields.FieldDoesNotExist:
+ if hasattr(field, key + '_lbl'):
+ field_name = key
+ field_verbose_name = getattr(field, key + '_lbl')
+ else:
+ continue
+ col_names.append(u'"%s"' % field_verbose_name)
+ extra_cols.append(self.COL_TPL % {'idx':field_name})
+ col_names = col_names and ",\n".join(col_names) or ""
+ col_idx = col_idx and ",\n".join(col_idx) or ""
+ extra_cols = extra_cols and ",\n".join(extra_cols) or ""
+ rendered += u"<table id='grid_%s' class='jqgrid'></table>\n"\
+ u"<div id='pager_%s'></div>\n"% (name, name)
+ encoding = settings.ENCODING or 'utf-8'
+ rendered += u"<div id='foot_%s' class='gridfooter'>\n" % name
+ if unicode(self.source_full):
+ rendered += u"%s (%s) <a href='%scsv' target='_blank'>%s</a> - "\
+ u"<a href='%scsv' target='_blank'>%s</a>\n" % (
+ unicode(_("Export as CSV")), encoding, unicode(self.source),
+ unicode(_(u"simple")), unicode(self.source_full),
+ unicode(_(u"full")),)
+ else:
+ rendered += u'<a href="%scsv" target="_blank">%s (%s)</a>\n' % (
+ unicode(self.source), unicode(_("Export as CSV")), encoding)
+ rendered += "</div>\n"
+ if self.multiple:
+ rendered += u'<input type="button" id="add_button_%s" value="%s"/>'\
+ u'<ul id="selectmulti_%s" class="selectmulti">\n</ul>\n' % (
+ name, unicode(_("Add")), name)
+ rendered += '<input type="hidden" id="hidden_%s" name="%s"/>\n' % (name,
+ name)
+ dct = {'name':name,
+ 'col_names':col_names,
+ 'extra_cols':extra_cols,
+ 'source':unicode(self.source),
+ 'col_idx':col_idx,
+ 'no_result':unicode(_("No results")),
+ 'loading':unicode(_("Loading...")),
+ 'remove':unicode(_(u"Remove")),
+ 'sname':name.replace('-', ''),
+ 'multi_cols': ",".join((u'"%d"' % col \
+ for col in self.multiple_cols))
+ }
+ rendered += """<script type="text/javascript">
+ var query_vars = new Array(%(col_idx)s);
+ var selItems_%(sname)s = new Array();
+ jQuery(document).ready(function(){
+ jQuery("#search_%(name)s").click(function (){
+ var data = "";
+ for (idx in query_vars)
+ {
+ var key = query_vars[idx];
+ var val = jQuery("#id_"+key).val();
+ if (val){
+ if (data) data += "&";
+ data += key + "=" + val;
+ }
+ }
+ var mygrid = jQuery("#grid_%(name)s");
+ var url = "%(source)s?submited=1&" + data;
+ mygrid.setGridParam({url:url});
+ mygrid.trigger("reloadGrid");
+ return false;
+ });
+
+ jQuery("#grid_%(name)s").jqGrid({
+ url:'%(source)s',
+ datatype: "json",
+ mtype: 'GET',
+ colNames:['id', '', %(col_names)s],
+ colModel:[
+ {name:'id', index:'id', hidden:true},
+ {name:'link', index:'link', width:80},
+ %(extra_cols)s
+ ],
+ sortname: 'value',
+ viewrecords: true,
+ sortorder: "asc",
+ emptyrecords: "%(no_result)s",
+ loadtext: "%(loading)s",
+ pager: '#pager_%(name)s',
+ width:740,
+ rowNum:20,
+ jsonReader : {repeatitems: false},
+ });
+ """ % dct
+ if self.multiple:
+ rendered += """
+ jQuery("#add_button_%(name)s").click(function (){
+ var mygrid = jQuery("#grid_%(name)s");
+ var idx = mygrid.getGridParam('selrow');
+ var lbl_cols = new Array(%(multi_cols)s);
+ var label = "";
+ for (var id in lbl_cols){
+ if(id == 1){
+ label += " (";
+ }else if (id > 1){
+ label += " ; ";
+ }
+ label += mygrid.getCell(idx, lbl_cols[id]);
+ }
+ if (id > 0){
+ label += ")";
+ }
+ for (id in selItems_%(sname)s){
+ if(selItems_%(sname)s[id] == idx){
+ return false;
+ }
+ }
+ selItems_%(sname)s.push(idx);
+ jQuery("#selectmulti_%(name)s").append(
+ "<li id='selected_%(name)s_"+idx+"'>\
+ <a href='#' class='remove' \
+ onclick=\\"multiRemoveItem(selItems_%(sname)s, '%(name)s', "+ idx +");\
+ return false;\\" title=\\"%(remove)s\\">X</a>" + label + "</li>");
+ return true;
+ });
+ jQuery("#submit_form").click(function (){
+ jQuery("#hidden_%(name)s").val(selItems_%(sname)s);
+ return true;
+ });
+ """ % dct
+ else:
+ rendered += """
+ jQuery("#submit_form").click(function (){
+ var mygrid = jQuery("#grid_%(name)s");
+ jQuery("#hidden_%(name)s").val(mygrid.getGridParam('selrow'));
+ return true;
+ });
+ """ % dct
+ rendered += "});\n</script>\n"
+ return mark_safe(rendered)
+
|