diff --git a/compilacao/forms.py b/compilacao/forms.py index 6e387e29a..2e048cb8f 100644 --- a/compilacao/forms.py +++ b/compilacao/forms.py @@ -1,7 +1,7 @@ from crispy_forms.helper import FormHelper from crispy_forms_foundation.layout import (HTML, Column, Div, Fieldset, - Layout, Row, Submit) + Layout, Row) from crispy_forms_foundation.layout.buttons import Button from crispy_forms_foundation.layout.fields import Field from django import forms @@ -9,10 +9,10 @@ from django.core.exceptions import NON_FIELD_ERRORS from django.forms.models import ModelForm from django.utils.translation import ugettext_lazy as _ -from compilacao import models from compilacao.models import (Dispositivo, Nota, TextoArticulado, TipoNota, - TipoTextoArticulado, TipoVide, Vide) -from compilacao.utils import to_column, to_fieldsets, to_row + TipoTextoArticulado, TipoVide, Vide, + PARTICIPACAO_SOCIAL_CHOICES) +from compilacao.utils import to_column, to_row, FormLayout class UpLoadImportFileForm(forms.Form): @@ -30,21 +30,6 @@ ta_error_messages = { } -class FormLayout(Layout): - - def __init__(self, *fields): - buttons = Div( - HTML('%s' % _('Cancelar')), - Submit('submit', _('Enviar'), - css_class='button radius success right'), - css_class='radius clearfix' - ) - _fields = list(to_fieldsets(fields)) + \ - [Row(Column(buttons, css_class='clearfix'))] - super(FormLayout, self).__init__(*_fields) - - class TaForm(ModelForm): tipo_ta = forms.ModelChoiceField( label=_('Tipo do Texto Articulado'), @@ -73,7 +58,7 @@ class TaForm(ModelForm): required=False) participacao_social = forms.NullBooleanField( label=_('Participação Social'), - widget=forms.Select(choices=models.PARTICIPACAO_SOCIAL_CHOICES), + widget=forms.Select(choices=PARTICIPACAO_SOCIAL_CHOICES), required=False) class Meta: diff --git a/compilacao/templatetags/compilacao_filters.py b/compilacao/templatetags/compilacao_filters.py index ed8eb757d..46726906a 100644 --- a/compilacao/templatetags/compilacao_filters.py +++ b/compilacao/templatetags/compilacao_filters.py @@ -1,9 +1,11 @@ +from compressor.utils import get_class from django import template from django.core.signing import Signer from django.db.models import Q from compilacao.models import Dispositivo, TipoDispositivo + register = template.Library() @@ -155,10 +157,22 @@ def nomenclatura_heranca(d, ignore_ultimo=0, ignore_primeiro=0): @register.simple_tag -def verbose_name(instance, field_name): +def field_verbose_name(instance, field_name): return instance._meta.get_field(field_name).verbose_name +@register.simple_tag +def model_verbose_name(class_name): + model = get_class('compilacao.models.' + class_name) + return model._meta.verbose_name + + +@register.simple_tag +def model_verbose_name_plural(class_name): + model = get_class('compilacao.models.' + class_name) + return model._meta.verbose_name_plural + + @register.filter def urldetail_content_type(obj): return '%s:detail' % obj.content_type.model diff --git a/compilacao/urls.py b/compilacao/urls.py index af134f869..148fb0a5b 100644 --- a/compilacao/urls.py +++ b/compilacao/urls.py @@ -1,6 +1,8 @@ from django.conf.urls import include, url from compilacao import views +from compilacao.views import tipo_nota_crud, tipo_vide_crud,\ + tipo_publicacao_crud, veiculo_publicacao_crud urlpatterns_compilacao = [ url(r'^$', views.TaListView.as_view(), name='ta_list'), @@ -11,6 +13,7 @@ urlpatterns_compilacao = [ url(r'^(?P[0-9]+)/delete$', views.TaDeleteView.as_view(), name='ta_delete'), + url(r'^(?P[0-9]+)/text$', views.TextView.as_view(), name='ta_text'), url(r'^(?P[0-9]+)/text/vigencia/(?P.+)/$', @@ -57,6 +60,17 @@ urlpatterns_compilacao = [ url(r'^(?P[0-9]+)/text/search$', views.DispositivoSearchFragmentFormView.as_view(), name='search_dispositivo'), + + + url(r'^config/tipo-nota/', + include(tipo_nota_crud.urls)), + url(r'^config/tipo-vide/', + include(tipo_vide_crud.urls)), + url(r'^config/tipo-publicacao/', + include(tipo_publicacao_crud.urls)), + url(r'^config/veiculo-publicacao/', + include(veiculo_publicacao_crud.urls)), + ] urlpatterns = [ diff --git a/compilacao/utils.py b/compilacao/utils.py index 244b27d55..8b7ddd3fd 100644 --- a/compilacao/utils.py +++ b/compilacao/utils.py @@ -1,5 +1,19 @@ +from braces.views import FormMessagesMixin +from crispy_forms.helper import FormHelper from crispy_forms_foundation.layout import Column, Fieldset, Row +from crispy_forms_foundation.layout.base import Layout, Div, HTML +from crispy_forms_foundation.layout.buttons import Submit +from django import forms +from django.conf.urls import url +from django.core.urlresolvers import reverse_lazy, reverse +from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ +from django.views.generic.detail import DetailView +from django.views.generic.edit import CreateView, UpdateView, DeleteView +from django.views.generic.list import ListView + + +NO_ENTRIES_MSG = _('Não existem registros') def to_column(name_span): @@ -88,3 +102,224 @@ def make_pagination(index, num_pages): None, num_pages - 1, num_pages] head = from_to(1, PAGINATION_LENGTH - len(tail) - 1) return head + [None] + tail + + +def get_field_display(obj, fieldname): + field = obj._meta.get_field(fieldname) + verbose_name = str(field.verbose_name) + if field.choices: + value = getattr(obj, 'get_%s_display' % fieldname)() + else: + value = getattr(obj, fieldname) + + if value is None: + display = '' + elif 'date' in str(type(value)): + display = value.strftime("%d/%m/%Y") + elif 'bool' in str(type(value)): + display = 'Sim' if value else 'Não' + else: + display = str(value) + + return verbose_name, display + + +class FormLayout(Layout): + + def __init__(self, *fields): + buttons = Div( + HTML('%s' % _('Cancelar')), + Submit('submit', _('Enviar'), + css_class='button radius success right'), + css_class='radius clearfix' + ) + _fields = list(to_fieldsets(fields)) + \ + [Row(Column(buttons, css_class='clearfix'))] + super(FormLayout, self).__init__(*_fields) + + +class Crud(object): + pass + + +def build_crud(model, help_path, layout): + crud = Crud() + crud.model = model + crud.help_path = help_path + crud.namespace = model._meta.model_name + + class CrispyForm(forms.ModelForm): + + class Meta: + model = crud.model + exclude = [] + + def __init__(self, *args, **kwargs): + super(CrispyForm, self).__init__(*args, **kwargs) + self.helper = FormHelper() + self.helper.layout = FormLayout(*layout) + + crud.model_form = CrispyForm + + def in_namespace(url_name): + return '%s:%s' % (crud.namespace, url_name) + + def make_form_invalid_message(msg): + return '%s %s' % (_('Formulário inválido.'), msg) + + class BaseMixin(object): + model = crud.model + + verbose_name = crud.model._meta.verbose_name + verbose_name_plural = crud.model._meta.verbose_name_plural + + list_url = reverse_lazy(in_namespace('list')) + create_url = reverse_lazy(in_namespace('create')) + help_path = crud.help_path # FIXME + + def get_url_for_this_object(self, url_name): + return reverse(in_namespace(url_name), args=(self.object.id,)) + + @property + def detail_url(self): + return self.get_url_for_this_object('detail') + + @property + def update_url(self): + return self.get_url_for_this_object('update') + + @property + def delete_url(self): + return self.get_url_for_this_object('delete') + + def get_template_names(self): + names = super(BaseMixin, self).get_template_names() + names.append("crud/%s.html" % + self.template_name_suffix.lstrip('_')) + return names + + class CrudListView(BaseMixin, ListView): + title = BaseMixin.verbose_name_plural + paginate_by = 10 + no_entries_msg = NO_ENTRIES_MSG + + @cached_property + def field_names(self): + '''The list of field names to display on table + + This base implementation returns the field names + in the first fieldset of the layout. + ''' + rows = layout[0][1:] + return [fieldname for row in rows for fieldname, __ in row] + + def get_rows(self, object_list): + return [[(get_field_display(obj, name)[1], + obj.pk if i == 0 else None) + for i, name in enumerate(self.field_names)] + for obj in object_list + ] + + def get_context_data(self, **kwargs): + context = super(CrudListView, self).get_context_data(**kwargs) + paginator = context['paginator'] + page_obj = context['page_obj'] + context['page_range'] = make_pagination( + page_obj.number, paginator.num_pages) + object_list = context['object_list'] + context['headers'] = [ + self.model._meta.get_field(fieldname).verbose_name + for fieldname in self.field_names] + context['rows'] = self.get_rows(object_list) + context['NO_ENTRIES_MSG'] = NO_ENTRIES_MSG + return context + + class CrudCreateView(BaseMixin, FormMessagesMixin, CreateView): + form_class = crud.model_form + title = _('Adicionar %(verbose_name)s') % { + 'verbose_name': BaseMixin.verbose_name} + form_valid_message = _('Registro criado com sucesso!') + form_invalid_message = make_form_invalid_message( + _('O registro não foi criado.')) + cancel_url = BaseMixin.list_url + + def form_invalid(self, form): + """ + If the form is invalid, re-render the context data with the + data-filled form and errors. + """ + print(form.errors) + return self.render_to_response(self.get_context_data(form=form)) + + def get_success_url(self): + return self.detail_url + + class CrudDetailView(BaseMixin, DetailView): + + @property + def title(self): + return self.get_object() + + def get_column(self, fieldname, span): + obj = self.get_object() + verbose_name, text = get_field_display(obj, fieldname) + return { + 'id': fieldname, + 'span': span, + 'verbose_name': verbose_name, + 'text': text, + } + + @property + def fieldsets(self): + return [ + {'legend': legend, + 'rows': [[self.get_column(fieldname, span) + for fieldname, span in row] + for row in rows] + } for legend, *rows in layout] + + class CrudUpdateView(BaseMixin, FormMessagesMixin, UpdateView): + form_class = crud.model_form + form_valid_message = _('Registro alterado com sucesso!') + form_invalid_message = make_form_invalid_message( + _('Suas alterações não foram salvas.')) + + @property + def title(self): + return self.get_object() + + def get_success_url(self): + return self.detail_url + + def cancel_url(self): + return self.detail_url + + class CrudDeleteView(BaseMixin, FormMessagesMixin, DeleteView): + form_valid_message = _('Registro excluído com sucesso!') + form_invalid_message = make_form_invalid_message( + _('O registro não foi excluído.')) + + def get_success_url(self): + return self.list_url + + crud.CrudListView = CrudListView + crud.CrudCreateView = CrudCreateView + crud.CrudDetailView = CrudDetailView + crud.CrudUpdateView = CrudUpdateView + crud.CrudDeleteView = CrudDeleteView + + # XXX transform into a property of Crud to enable override + crud.urlpatterns = [ + url(r'^$', CrudListView.as_view(), name='list'), + url(r'^create$', CrudCreateView.as_view(), name='create'), + url(r'^(?P\d+)$', CrudDetailView.as_view(), name='detail'), + url(r'^(?P\d+)/edit$', + CrudUpdateView.as_view(), name='update'), + url(r'^(?P\d+)/delete$', + CrudDeleteView.as_view(), name='delete'), + ] + crud.urls = crud.urlpatterns, crud.namespace, crud.namespace + + return crud diff --git a/compilacao/views.py b/compilacao/views.py index 1d45ef15e..8738544e1 100644 --- a/compilacao/views.py +++ b/compilacao/views.py @@ -1,6 +1,6 @@ -import sys from collections import OrderedDict from datetime import datetime, timedelta +import sys from braces.views import FormMessagesMixin from django.contrib.auth.decorators import login_required @@ -23,7 +23,10 @@ from compilacao import forms, utils from compilacao.models import (Dispositivo, Nota, PerfilEstruturalTextoArticulado, TextoArticulado, TipoDispositivo, TipoNota, - TipoTextoArticulado, Vide) + TipoTextoArticulado, Vide, TipoVide, + TipoPublicacao, VeiculoPublicacao) +from compilacao.utils import build_crud + DISPOSITIVO_SELECT_RELATED = ( 'tipo_dispositivo', @@ -36,6 +39,36 @@ DISPOSITIVO_SELECT_RELATED = ( 'dispositivo_pai', 'dispositivo_pai__tipo_dispositivo') +tipo_nota_crud = build_crud( + TipoNota, 'tipo_nota', [ + + [_('Tipo da Nota'), + [('sigla', 2), ('nome', 10)], + [('modelo', 12)]], + ]) + +tipo_vide_crud = build_crud( + TipoVide, 'tipo_vide', [ + + [_('Tipo de Vide'), + [('sigla', 2), ('nome', 10)]], + ]) + +tipo_publicacao_crud = build_crud( + TipoPublicacao, 'tipo_publicacao', [ + + [_('Tipo de Publicação'), + [('sigla', 2), ('nome', 10)]], + ]) + + +veiculo_publicacao_crud = build_crud( + VeiculoPublicacao, 'veiculo_publicacao', [ + + [_('Veículo de Publicação'), + [('sigla', 2), ('nome', 10)]], + ]) + class TaListView(ListView): model = TextoArticulado @@ -58,7 +91,7 @@ class TaDetailView(DetailView): @property def title(self): - if self.object.content_object: + if self.get_object().content_object: return _( 'Metadados para o Texto Articulado da %s - %s') % ( self.get_object().content_object._meta.verbose_name_plural, @@ -349,10 +382,6 @@ class TextView(ListView): return self.itens_de_vigencia - def get_ta(self): - return TextoArticulado.objects.select_related('tipo_ta').get( - pk=self.kwargs['ta_id']) - def is_ta_alterador(self): if self.flag_alteradora == -1: self.flag_alteradora = Dispositivo.objects.select_related( diff --git a/compilacao/views2.py b/compilacao/views2.py index ab71973be..c1b2d6169 100644 --- a/compilacao/views2.py +++ b/compilacao/views2.py @@ -5,38 +5,6 @@ from compilacao.models import (PerfilEstruturalTextoArticulado, TipoVide, VeiculoPublicacao) from sapl.crud import build_crud -DISPOSITIVO_SELECT_RELATED = ( - 'tipo_dispositivo', - 'ta_publicado', - 'ta', - 'dispositivo_atualizador', - 'dispositivo_atualizador__dispositivo_pai', - 'dispositivo_atualizador__dispositivo_pai__ta', - 'dispositivo_atualizador__dispositivo_pai__ta__tipo', - 'dispositivo_pai', - 'dispositivo_pai__tipo_dispositivo') - -tipo_nota_crud = build_crud( - TipoNota, 'tipo_nota', [ - - [_('Tipo da Nota'), - [('sigla', 2), ('nome', 10)], - [('modelo', 12)]], - ]) - -tipo_vide_crud = build_crud( - TipoVide, 'tipo_vide', [ - - [_('Tipo de Vide'), - [('sigla', 2), ('nome', 10)]], - ]) - -tipo_publicacao_crud = build_crud( - TipoPublicacao, 'tipo_publicacao', [ - - [_('Tipo de Publicação'), - [('sigla', 2), ('nome', 10)]], - ]) perfil_estr_txt_norm = build_crud( PerfilEstruturalTextoArticulado, 'perfil_estrutural', [ @@ -46,13 +14,6 @@ perfil_estr_txt_norm = build_crud( ]) -veiculo_publicacao_crud = build_crud( - VeiculoPublicacao, 'veiculo_publicacao', [ - - [_('Veículo de Publicação'), - [('sigla', 2), ('nome', 10)]], - ]) - tipo_dispositivo_crud = build_crud( TipoDispositivo, 'tipo_dispositivo', [ diff --git a/static/img/ajax-loader.gif b/static/img/ajax-loader.gif deleted file mode 100644 index 812bcf757..000000000 Binary files a/static/img/ajax-loader.gif and /dev/null differ diff --git a/static/js/compilacao.js b/static/js/compilacao.js index 6cd8fc345..2a76a1acb 100644 --- a/static/js/compilacao.js +++ b/static/js/compilacao.js @@ -35,5 +35,6 @@ function ReadCookie(cookieName) { } function insertWaitAjax(element) { - jQuery(element).append('
'); + //jQuery(element).append('
'); + jQuery(element).append('
'); } diff --git a/static/js/compilacao_view.js b/static/js/compilacao_view.js index 55f474dd7..7ec934789 100644 --- a/static/js/compilacao_view.js +++ b/static/js/compilacao_view.js @@ -154,7 +154,10 @@ $(document).ready(function() { $(".dpt").css("font-size", "+=1"); }); + $(".dpt").each(function() { + var nivel = parseInt($(this).attr('nivel')); + $(this).css('z-index', 20-nivel) - + }); }); diff --git a/static/styles/app.scss b/static/styles/app.scss index cd874a6a0..cf3b64f0b 100644 --- a/static/styles/app.scss +++ b/static/styles/app.scss @@ -198,13 +198,6 @@ box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 1px 4px rgba(0, 0, 0, 0.23); max-width: 960px; } -.sub-nav { - dt a, dd a, li a { - color: white !important; - } -} - - .icon-bar { vertical-align: top; } @@ -262,10 +255,6 @@ font-size: 100%; height: 100%; background-color: #ffffff; } - - .content a:hover { - color: #444444; - } /* Layout */ .footer { diff --git a/static/styles/compilacao.scss b/static/styles/compilacao.scss index c46dcdeef..5b3bebf16 100644 --- a/static/styles/compilacao.scss +++ b/static/styles/compilacao.scss @@ -221,7 +221,6 @@ a:link:after, a:visited:after { font-size: 1.15em; float:left; .dptt { - z-index: 8; position: relative; } } @@ -398,7 +397,7 @@ a:link:after, a:visited:after { left: -1.6em; right: -1.6em; background-color: #2980b9; - z-index: 8; + z-index: 18; * { font-size: 0.8rem; @@ -419,7 +418,7 @@ a:link:after, a:visited:after { border-spacing: 0; top: 0px; right: 0px; - z-index: 9; + z-index: 19; li { display: table-cell; background-color: $color_buttons; @@ -447,7 +446,7 @@ a:link:after, a:visited:after { margin: 1em 0 2em 0; padding: 0em; border: 0px; - z-index: 9; + z-index: 19; ul.btns-action { display: none; } @@ -895,7 +894,7 @@ a:link:after, a:visited:after { padding: 0.3em; font-size: 80%; text-align: right; - z-index: 5; + z-index: 15; display: table; li { display: table-cell; @@ -903,7 +902,7 @@ a:link:after, a:visited:after { } .actions_parents { - z-index: 1; + z-index: 11; top: 0em; left: 0em; a { @@ -989,7 +988,7 @@ a:link:after, a:visited:after { .actions_inserts { background: transparent; position: relative; - z-index: 9; + z-index: 19; display: table; width: 100%; @@ -1023,7 +1022,7 @@ a:link:after, a:visited:after { } &::before { - z-index: 10; + z-index: 20; position: absolute; background: url(/static/img/icon_delete_white.png) no-repeat 50% 50%; content:""; @@ -1327,7 +1326,8 @@ a:link:after, a:visited:after { } @media print { - .cp .vigencias { + .cp .vigencias, .toggle-topbar, .menu-icon, .button { display:none; } + } diff --git a/templates/compilacao/text_edit.html b/templates/compilacao/text_edit.html index 2597d772c..1004b7c59 100644 --- a/templates/compilacao/text_edit.html +++ b/templates/compilacao/text_edit.html @@ -14,12 +14,14 @@ {% block title%} -

Edição: {{ view.get_ta }} - {% trans 'Texto Multivigente' %}

+

Edição: {{ view.title }} - {% trans 'Texto Multivigente' %}

{% endblock %} {% block sections_nav %}{{block.super}} + {% if not object.content_object%}
{% trans 'Texto' %}
+ {%endif %} {% endblock %} {% block base_content %}{{block.super}} diff --git a/templates/compilacao/text_list.html b/templates/compilacao/text_list.html index 71b234a45..1e8884b4d 100644 --- a/templates/compilacao/text_list.html +++ b/templates/compilacao/text_list.html @@ -20,15 +20,16 @@
{% trans 'Edição' %}
{% endblock %} +{% block actions %}{% endblock %} + {% block base_content %}{{block.super}} - {% block actions %}{% endblock %}
{% if object_list %} -
- a - A -
+
    +
  • a
  • +
  • A
  • +
{% endif %} {% for key, values in view.get_vigencias.items %} diff --git a/templates/compilacao/text_list_bloco.html b/templates/compilacao/text_list_bloco.html index 6c614dd73..bb1d5f5b2 100644 --- a/templates/compilacao/text_list_bloco.html +++ b/templates/compilacao/text_list_bloco.html @@ -13,7 +13,7 @@ {% if forloop.first and view|isinst:'DispositivoView' %} {% else %} -
+
{% endif%} {% spaceless %} @@ -28,9 +28,10 @@ {% endif %} {% if user.is_authenticated and not dpt.tipo_dispositivo.dispositivo_de_articulacao%} - {% if perms.compilacao.add_nota or perms.compilacao.add_vide %} + {% if perms.compilacao.add_nota or perms.compilacao.add_vide or perms.compilacao.change_dispositivo%}
{# TODO: User - dne - Dispostivo Nota Editor - tratar permissão de usuário#}
    + {% if perms.compilacao.change_dispositivo %}
  • Ed
  • {% endif %} {% if perms.compilacao.add_nota %}
  • N
  • {% endif %} {% if perms.compilacao.add_vide %}
  • V
  • {% endif %}
diff --git a/templates/compilacao/text_list_blocoalteracao.html b/templates/compilacao/text_list_blocoalteracao.html index 0c099a22e..86ceacb3c 100644 --- a/templates/compilacao/text_list_blocoalteracao.html +++ b/templates/compilacao/text_list_blocoalteracao.html @@ -1,12 +1,13 @@ {% load compilacao_filters %} + {% for ch in dpt.pk|get_bloco_atualizador %} {% spaceless %} {% if ch.visibilidade %} -
-
- {{ ch.tipo_dispositivo.rotulo_prefixo_html|safe }}{{ ch.rotulo }}{{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }}{{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{{ ch.texto|safe }} -
-
- {%endif%} +
+
+ {{ ch.tipo_dispositivo.rotulo_prefixo_html|safe }}{{ ch.rotulo }}{{ ch.tipo_dispositivo.rotulo_sufixo_html|safe }}{{ ch.tipo_dispositivo.texto_prefixo_html|safe }}{{ ch.texto|safe }} +
+
+ {%endif%} {% endspaceless %} {% endfor %} diff --git a/templates/compilacao/textoarticulado_detail.html b/templates/compilacao/textoarticulado_detail.html index eb3b4baff..4a1b0d48f 100644 --- a/templates/compilacao/textoarticulado_detail.html +++ b/templates/compilacao/textoarticulado_detail.html @@ -3,10 +3,19 @@ {% block base_content %} {# FIXME is this the best markup to use? #} @@ -27,7 +38,7 @@
- +

{{ object.tipo_ta}}

@@ -35,7 +46,7 @@ {% if object.content_object and object.content_object.tipo%}
- +

{{ object.content_object.tipo}}

@@ -43,21 +54,21 @@
- +

{{ object.numero}}

- +

{{ object.ano}}

- +

{{ object.data}}

@@ -66,7 +77,7 @@
- +

{{ object.ementa|safe}}

diff --git a/templates/compilacao/textoarticulado_list.html b/templates/compilacao/textoarticulado_list.html index 070ec3ff7..edbd3c44e 100644 --- a/templates/compilacao/textoarticulado_list.html +++ b/templates/compilacao/textoarticulado_list.html @@ -1,15 +1,32 @@ -{% extends "base.html" %} {% load i18n %} {% block base_content %} +{% extends "base.html" %} +{% load i18n %} +{% load compilacao_filters %} + +{% block base_content %} {# FIXME is this the best markup to use? #} + + + + diff --git a/templates/index.html b/templates/index.html index 1d9bbb274..af44e3dfd 100644 --- a/templates/index.html +++ b/templates/index.html @@ -4,4 +4,3 @@ {% block title%}

Bem-vindo ao SAPL!

{% endblock %} -