Browse Source

Diversas funcionalidades

- implementação dos botões excluir na edição de dispositivos
- implementação de perfis estruturais de textos normativos
- refatoração do algoritmo de seleção de provaveis inserções
- refatoração do algoritimo de inserção
- parte da implementação do parser básico para import de arquivos odf
pull/10/head
LeandroRoberto 9 years ago
parent
commit
b5b9838913
  1. 327
      compilacao/file2dispositivo.py
  2. 24
      compilacao/migrations/0015_auto_20151115_2310.py
  3. 48
      compilacao/migrations/0016_auto_20151119_0950.py
  4. 28
      compilacao/migrations/0017_auto_20151119_1035.py
  5. 23
      compilacao/migrations/0018_auto_20151119_1052.py
  6. 20
      compilacao/migrations/0019_auto_20151119_1120.py
  7. 20
      compilacao/migrations/0020_auto_20151119_1126.py
  8. 23
      compilacao/migrations/0021_auto_20151119_1617.py
  9. 98
      compilacao/models.py
  10. 16
      compilacao/templatetags/compilacao_filters.py
  11. 8
      compilacao/urls.py
  12. 240
      compilacao/views.py
  13. 1
      requirements/requirements.txt
  14. 35
      static/js/compilacao.js
  15. 92
      static/styles/compilacao.scss
  16. 31
      templates/compilacao/edit.html
  17. 36
      templates/compilacao/edit_bloco.html
  18. 5
      templates/compilacao/index.html
  19. 1
      templates/sistema.html

327
compilacao/file2dispositivo.py

@ -0,0 +1,327 @@
import re
from odf.element import Node, Text
from odf.opendocument import load
from odf.table import Table, TableCell, TableRow
from odf.text import (List, ListHeader, ListItem, ListLevelStyleBullet,
ListLevelStyleNumber, ListStyle, Note)
from sapl import utils
class Parser(object):
parser_list = []
def parser(self, _filepath):
self.filepath = _filepath
return self.re_parser()
def re_parser(self):
self.parser_list = []
# odt identificado pela extensão ou teste caso o arquivo sem extensão
if self.filepath.endswith('.odt') or\
not re.search(r"(\w+)\.(\w+)", self.filepath):
try:
odtparser = OdtParser()
self.parser_list = odtparser.parser(self.filepath)
return self.parser_list
except Exception as e:
print(e)
# TODO: Continue para outros formatos
pass
# doc identificado pela extensão ou teste caso o arquivo sem extensão
if self.filepath.endswith(('.doc', 'docx')) or\
not re.search(r"(\w+)\.(\w+)", self.filepath):
try:
# TODO
return []
except Exception as e:
# TODO: Continue para outros formatos
pass
return []
def _reduce_terms(self, _nodes=None, level=0):
print(level)
if not _nodes:
nodes = self.parser_list
else:
nodes = _nodes
fstr = True
i = -1
for nd in nodes:
i += 1
# print(nd)
if not _nodes:
fstr = False
if nd[0] == 'table:table':
continue
if isinstance(nd, list):
fstr = False
nodes[i] = self._reduce_terms(nd, level=level + 1)
if fstr:
return ' '.join(nodes)
return nodes
class OdtParser(Parser):
FNC1 = '1'
FNCI = 'I'
FNCi = 'i'
FNCA = 'A'
FNCa = 'a'
FNC8 = '*'
FNCN = 'N'
def re_parser(self):
self.textdoc = load(self.filepath)
self.level_list = 0
self.control_list = {}
# mm = ODF2MoinMoin(self.filepath)
# self.parser_list = [mm.toString(), ]
self.parser_list = self._import_itens(self.textdoc.text, level=0)
# self._reduce_terms()
return self.parser_list
def _import_itens(self, element, level=0):
try:
result = []
for el in element.childNodes:
print(level, el.tagName)
_r = ''
if el.tagName == 'Text':
_r = str(el)
else:
if el.isInstanceOf(Note):
continue
elif el.isInstanceOf(Table):
_r = self._import_table(el, level=level + 1)
elif el.isInstanceOf(List):
_r = self._import_list(el, level=level + 1)
# elif el.isInstanceOf(P):
# _r = [self.extractText(el),]
elif el.hasChildNodes():
_r = self._import_itens(el, level=level + 1)
else:
_r = str(el)
if _r:
if isinstance(_r, str):
result += [_r, ]
else:
result += _r
return result
except Exception as e:
print(e)
def _import_table(self, element, level=0):
result = ''
print(level)
try:
if element.isInstanceOf(Table):
result += '<table width="100%">'
for el in element.childNodes:
_r = ''
if isinstance(el, Text):
_r = str(el)
else:
if el.isInstanceOf(TableRow):
_r = self._import_table(el, level=level + 1)
_r = '<tr>%s</tr>' % (''.join(_r))
result += ''.join(_r)
elif el.isInstanceOf(TableCell):
_r = self._import_table(el, level=level + 1)
if el.getAttribute('numberrowsspanned'):
_r = '<td rowspan="%s">%s</td>' % (
el.getAttribute('numberrowsspanned'),
''.join(_r))
elif el.getAttribute('numbercolumnsspanned'):
_r = '<td colspan="%s">%s</td>' % (
el.getAttribute('numbercolumnsspanned'),
''.join(_r))
else:
_r = '<td>%s</td>' % (''.join(_r))
result += ''.join(_r)
else:
_r = self.extractText(el)
# _r = self._reduce_terms(_r)
if isinstance(_r, list):
result += '<br>'.join(_r)
else:
if _r:
result += _r + '<br>'
if element.isInstanceOf(Table):
result += '</table>'
return [result, ]
except Exception as e:
print(e)
def _import_list(self, element, level=0):
self.level_list += 1
result = []
print(level)
numsufixo = ''
numformat = ''
startvalue = ''
count_list_item = 0
try:
if element.isInstanceOf(List):
_stylename = element.getAttribute('stylename')
if _stylename:
self.stylename = _stylename
liststyles = self.textdoc.getElementsByType(ListStyle)
for liststyle in liststyles:
if liststyle.getAttribute('name') == self.stylename:
break
stylesnumbers = liststyle.getElementsByType(
ListLevelStyleNumber)
for item in stylesnumbers:
if item.getAttribute('level') == str(self.level_list):
numsufixo = item.getAttribute('numsuffix') or ''
numformat = item.getAttribute('numformat') or ''
startvalue = item.getAttribute('startvalue') or ''
break
if not numformat:
stylesbullets = liststyle.getElementsByType(
ListLevelStyleBullet)
for item in stylesbullets:
if item.getAttribute('level') == str(self.level_list):
numformat = '*'
break
_id = element.getAttribute('id')
if _id:
self.id_last_list = _id
if self.id_last_list not in self.control_list:
self.control_list[self.id_last_list] = [0, ] * 10
if _id:
if not element.getAttribute('continuelist') and\
self.level_list == 1:
self.control_list[self.id_last_list] = [0, ] * 10
except Exception as e:
print(e)
try:
flag_first = True
for el in element.childNodes:
prefixo = ''
if isinstance(el, Text):
_r = [str(el), ]
else:
if el.isInstanceOf(ListHeader) or\
el.isInstanceOf(ListItem):
if startvalue and flag_first:
self.control_list[self.id_last_list][
self.level_list - 1] = int(startvalue) - 1
flag_first = False
self.control_list[self.id_last_list][
self.level_list - 1] += 1
count_list_item = self.control_list[self.id_last_list][
self.level_list - 1]
if numformat == OdtParser.FNC1:
prefixo = str(count_list_item)
elif numformat == OdtParser.FNCI:
prefixo = utils.int_to_roman(count_list_item)
elif numformat == OdtParser.FNCi:
prefixo = utils.int_to_roman(
count_list_item).lower()
elif numformat == OdtParser.FNCA:
prefixo = utils.int_to_letter(count_list_item)
elif numformat == OdtParser.FNCa:
prefixo = utils.int_to_letter(
count_list_item).lower()
elif numformat == OdtParser.FNC8:
prefixo = '*'
else:
prefixo = str(count_list_item)
prefixo += numsufixo
_r = self._import_itens(el, level=level + 1)
if _r:
if prefixo:
_r[0] = '%s %s' % (prefixo, _r[0])
result += _r
else:
result += _r
self.level_list -= 1
return result
except Exception as e:
print(e)
def extractText(self, odfElement):
""" Extract text content from an Element, with whitespace represented
properly. Returns the text, with tabs, spaces, and newlines
correctly evaluated. This method recursively descends through the
children of the given element, accumulating text and "unwrapping"
<text:s>, <text:tab>, and <text:line-break> elements along the way.
"""
result = []
if len(odfElement.childNodes) != 0:
for child in odfElement.childNodes:
if child.nodeType == Node.TEXT_NODE:
result.append(child.data)
elif child.nodeType == Node.ELEMENT_NODE:
subElement = child
tagName = subElement.qname
if tagName == (u"urn:oasis:names:tc:opendocument:xmlns:" +
"text:1.0", u"line-break"):
result.append("\n")
elif tagName == (u"urn:oasis:names:tc:opendocument:" +
"xmlns:text:1.0", u"tab"):
result.append("\t")
elif tagName == (u"urn:oasis:names:tc:opendocument:" +
"xmlns:text:1.0", u"s"):
c = subElement.getAttribute('c')
if c:
spaceCount = int(c)
else:
spaceCount = 1
result.append(" " * spaceCount)
else:
result.append(self.extractText(subElement))
return ''.join(result)

24
compilacao/migrations/0015_auto_20151115_2310.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0014_auto_20151107_1836'),
]
operations = [
migrations.AddField(
model_name='tipodispositivo',
name='dispositivo_de_alteracao',
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, verbose_name='Dispositivo de Alteração'),
),
migrations.AlterField(
model_name='tipodispositivorelationship',
name='filho_permitido',
field=models.ForeignKey(related_name='possiveis_pais', to='compilacao.TipoDispositivo'),
),
]

48
compilacao/migrations/0016_auto_20151119_0950.py

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import datetime
from django.utils.timezone import utc
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0015_auto_20151115_2310'),
]
operations = [
migrations.CreateModel(
name='PerfilEstruturalTextosNormativos',
fields=[
('id', models.AutoField(auto_created=True, serialize=False, primary_key=True, verbose_name='ID')),
('nome', models.CharField(max_length=50, verbose_name='Nome')),
],
options={
'verbose_name_plural': 'Perfis Estruturais de Textos Normativos',
'verbose_name': 'Perfil Estrutural de Textos Normativos',
},
),
migrations.RemoveField(
model_name='dispositivo',
name='timestamp',
),
migrations.AddField(
model_name='dispositivo',
name='created',
field=models.DateTimeField(default=datetime.datetime(2015, 11, 19, 11, 49, 55, 455058, tzinfo=utc), auto_now_add=True, verbose_name='created'),
preserve_default=False,
),
migrations.AddField(
model_name='dispositivo',
name='modified',
field=models.DateTimeField(auto_now=True, default=datetime.datetime(2015, 11, 19, 11, 50, 5, 86839, tzinfo=utc), verbose_name='modified'),
preserve_default=False,
),
migrations.AddField(
model_name='tipodispositivorelationship',
name='perfil',
field=models.ForeignKey(blank=True, related_name='+', null=True, default=None, to='compilacao.PerfilEstruturalTextosNormativos'),
),
]

28
compilacao/migrations/0017_auto_20151119_1035.py

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0016_auto_20151119_0950'),
]
operations = [
migrations.AddField(
model_name='perfilestruturaltextosnormativos',
name='padrao',
field=models.BooleanField(verbose_name='Padrão', choices=[(True, 'Sim'), (False, 'Não')], default=False),
),
migrations.AlterField(
model_name='tipodispositivorelationship',
name='perfil',
field=models.ForeignKey(to='compilacao.PerfilEstruturalTextosNormativos'),
),
migrations.AlterUniqueTogether(
name='tipodispositivorelationship',
unique_together=set([('pai', 'filho_permitido', 'perfil')]),
),
]

23
compilacao/migrations/0018_auto_20151119_1052.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0017_auto_20151119_1035'),
]
operations = [
migrations.RemoveField(
model_name='tipodispositivo',
name='quantidade_permitida',
),
migrations.AddField(
model_name='tipodispositivorelationship',
name='quantidade_permitida',
field=models.IntegerField(default=-1, verbose_name='Quantidade permitida nesta relação'),
),
]

20
compilacao/migrations/0019_auto_20151119_1120.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0018_auto_20151119_1052'),
]
operations = [
migrations.AddField(
model_name='perfilestruturaltextosnormativos',
name='sigla',
field=models.CharField(max_length=10, verbose_name='Sigla', default='LC95'),
preserve_default=False,
),
]

20
compilacao/migrations/0020_auto_20151119_1126.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0019_auto_20151119_1120'),
]
operations = [
migrations.AlterField(
model_name='perfilestruturaltextosnormativos',
name='sigla',
field=models.CharField(
max_length=10, verbose_name='Sigla', unique=True),
),
]

23
compilacao/migrations/0021_auto_20151119_1617.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0020_auto_20151119_1126'),
]
operations = [
migrations.AlterModelOptions(
name='perfilestruturaltextosnormativos',
options={'verbose_name': 'Perfil Estrutural de Textos Normativos', 'verbose_name_plural': 'Perfis Estruturais de Textos Normativos', 'ordering': ['-padrao', 'sigla']},
),
migrations.AddField(
model_name='tipodispositivorelationship',
name='permitir_variacao',
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], verbose_name='Permitir Variação Numérica', default=True),
),
]

98
compilacao/models.py

@ -11,6 +11,17 @@ from sapl import utils
from sapl.utils import YES_NO_CHOICES
class TimestampedMixin(models.Model):
created = models.DateTimeField(
verbose_name=_('created'),
editable=False, blank=True, auto_now_add=True)
modified = models.DateTimeField(
verbose_name=_('modified'), editable=False, blank=True, auto_now=True)
class Meta:
abstract = True
class BaseModel(models.Model):
class Meta:
@ -77,12 +88,6 @@ class TipoVide(models.Model):
class TipoDispositivo(BaseModel):
"""
- para class_css articulacao, omissis, ementa,
bloco_alteracao, artigo, caput e paragrafo
são palavras chaves usadas no código e de existência obrigatória.
- apenas articulacao recebe nivel zero
- no attributo rotulo_prefixo_texto, caso haja um ';' (ponto e vírgula), e
pode haver 1 ';', o método [def rotulo_padrao] considerará que o
rótulo do dispositivo deverá ser escrito com o contéudo após o ';'
@ -200,6 +205,10 @@ class TipoDispositivo(BaseModel):
choices=YES_NO_CHOICES,
default=False,
verbose_name=_('Dispositivo de Articulação (Sem Texto)'))
dispositivo_de_alteracao = models.BooleanField(
choices=YES_NO_CHOICES,
default=False,
verbose_name=_('Dispositivo de Alteração'))
formato_variacao0 = models.CharField(
max_length=1,
choices=FORMATO_NUMERACAO_CHOICES,
@ -238,10 +247,6 @@ class TipoDispositivo(BaseModel):
symmetrical=False,
related_name='+')
quantidade_permitida = models.IntegerField(
default=-1,
verbose_name=_('Quantidade permitida dentro de uma Norma'))
class Meta:
verbose_name = _('Tipo de Dispositivo')
verbose_name_plural = _('Tipos de Dispositivo')
@ -250,32 +255,86 @@ class TipoDispositivo(BaseModel):
def __str__(self):
return self.nome
def permitido_inserir_in(self, base, excluir_autos=False):
pp = self.possiveis_pais.filter(pai=base)
def permitido_inserir_in(
self, base, include_relative_autos=True, perfil_pk=None):
if not perfil_pk:
perfis = PerfilEstruturalTextosNormativos.objects.filter(
padrao=True)[:1]
if not perfis.exists():
return False
perfil_pk = perfis[0].pk
pp = self.possiveis_pais.filter(pai=base, perfil_id=perfil_pk)
if pp.exists():
if excluir_autos:
if not include_relative_autos:
if pp[0].filho_de_insercao_automatica:
return False
return True
return False
def permitido_variacao(
self, base, perfil_pk=None):
if not perfil_pk:
perfis = PerfilEstruturalTextosNormativos.objects.filter(
padrao=True)[:1]
if not perfis.exists():
return False
perfil_pk = perfis[0].pk
pp = self.possiveis_pais.filter(pai=base, perfil_id=perfil_pk)
if pp.exists():
if pp[0].permitir_variacao:
return True
return False
class PerfilEstruturalTextosNormativos(BaseModel):
sigla = models.CharField(
max_length=10, unique=True, verbose_name=_('Sigla'))
nome = models.CharField(max_length=50, verbose_name=_('Nome'))
padrao = models.BooleanField(
default=False,
choices=YES_NO_CHOICES, verbose_name=_('Padrão'))
class Meta:
verbose_name = _('Perfil Estrutural de Textos Normativos')
verbose_name_plural = _('Perfis Estruturais de Textos Normativos')
ordering = ['-padrao', 'sigla']
def __str__(self):
return self.nome
class TipoDispositivoRelationship(BaseModel):
pai = models.ForeignKey(TipoDispositivo, related_name='filhos_permitidos')
filho_permitido = models.ForeignKey(
TipoDispositivo,
blank=True, null=True, default=None,
related_name='possiveis_pais')
perfil = models.ForeignKey(PerfilEstruturalTextosNormativos)
filho_de_insercao_automatica = models.BooleanField(
default=False,
choices=YES_NO_CHOICES, verbose_name=_('Filho de Inserção Automática'))
permitir_variacao = models.BooleanField(
default=True,
choices=YES_NO_CHOICES, verbose_name=_('Permitir Variação Numérica'))
quantidade_permitida = models.IntegerField(
default=-1,
verbose_name=_('Quantidade permitida nesta relação'))
class Meta:
verbose_name = _('Relação Direta Permitida')
verbose_name_plural = _('Relaçõe Diretas Permitidas')
ordering = ['pai', 'filho_permitido']
unique_together = (
('pai', 'filho_permitido',),)
('pai', 'filho_permitido', 'perfil'),)
def __str__(self):
return '%s - %s' % (
@ -331,7 +390,7 @@ class Publicacao(models.Model):
return '%s: %s' % (self.veiculo_publicacao, self.publicacao)
class Dispositivo(BaseModel):
class Dispositivo(BaseModel, TimestampedMixin):
TEXTO_PADRAO_DISPOSITIVO_REVOGADO = _('(Revogado)')
INTERVALO_ORDEM = 1000
ordem = models.PositiveIntegerField(
@ -411,8 +470,6 @@ class Dispositivo(BaseModel):
choices=YES_NO_CHOICES,
verbose_name=_('Visibilidade na Norma Publicada'))
timestamp = models.DateTimeField()
tipo_dispositivo = models.ForeignKey(
TipoDispositivo,
related_name='dispositivos_do_tipo_set',
@ -894,11 +951,12 @@ class Dispositivo(BaseModel):
return proxima_articulacao[0]
def is_relative_auto_insert(self):
def is_relative_auto_insert(self, perfil_pk):
if self.dispositivo_pai is not None:
# pp possiveis_pais
pp = self.tipo_dispositivo.possiveis_pais.filter(
pai=self.dispositivo_pai.tipo_dispositivo)
pai=self.dispositivo_pai.tipo_dispositivo,
perfil_id=perfil_pk)
if pp.exists():
if pp[0].filho_de_insercao_automatica:

16
compilacao/templatetags/compilacao_filters.py

@ -46,6 +46,8 @@ def nota_automatica(dispositivo):
d = dispositivo.dispositivo_atualizador.dispositivo_pai
if dispositivo.texto == Dispositivo.TEXTO_PADRAO_DISPOSITIVO_REVOGADO:
return 'Revogado pelo %s.' % d
elif not dispositivo.dispositivo_substituido:
return 'Inclusão feita pelo %s.' % d
else:
return 'Alteração feita pelo %s.' % d
return ''
@ -69,6 +71,16 @@ def get_sign_vigencia(value):
return signer.sign(str(string))
@register.filter
def select_provaveis_inserts(view, request):
return view.select_provaveis_inserts(request)
@register.filter
def is_relative_auto_insert(dpt, request):
return dpt.is_relative_auto_insert(request.session.perfil_estrutural)
@register.filter
def isinst(value, class_str):
classe = value.__class__.__name__
@ -82,11 +94,11 @@ def render_actions_head(view, d_atual):
return False
# Menu
if view.pk_view == view.pk_add and d_atual.pk == view.pk_view:
if view.pk_view == view.pk_edit and d_atual.pk == view.pk_view:
return True
# conteudo e menu no filho
if view.pk_view != view.pk_add and d_atual.pk == view.pk_add:
if view.pk_view != view.pk_edit and d_atual.pk == view.pk_edit:
return True
return False

8
compilacao/urls.py

@ -1,9 +1,9 @@
from django.conf.urls import include, url
from compilacao import views
from compilacao.views import (tipo_dispositivo_crud, tipo_nota_crud,
tipo_publicacao_crud, tipo_vide_crud,
veiculo_publicacao_crud)
from compilacao.views import (perfil_estr_txt_norm, tipo_dispositivo_crud,
tipo_nota_crud, tipo_publicacao_crud,
tipo_vide_crud, veiculo_publicacao_crud)
urlpatterns_compilacao = [
url(r'^(?P<norma_id>[0-9]+)/compilacao$',
@ -37,4 +37,6 @@ urlpatterns = [
include(tipo_dispositivo_crud.urls)),
url(r'^sistema/compilacao/veiculo-publicacao/',
include(veiculo_publicacao_crud.urls)),
url(r'^sistema/compilacao/perfil-estrutural-textos-normativos/',
include(perfil_estr_txt_norm.urls)),
]

240
compilacao/views.py

@ -2,17 +2,21 @@ from collections import OrderedDict
from datetime import datetime, timedelta
from os.path import sys
from django import forms
from django.core.signing import Signer
from django.db.models import Q
from django.http.response import JsonResponse
from django.shortcuts import render
from django.utils.dateparse import parse_date
from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import TemplateView
from django.views.generic.edit import FormMixin
from django.views.generic.list import ListView
from compilacao.models import (Dispositivo, TipoDispositivo, TipoNota,
TipoPublicacao, TipoVide, VeiculoPublicacao)
from compilacao.file2dispositivo import Parser
from compilacao.models import (Dispositivo, PerfilEstruturalTextosNormativos,
TipoDispositivo, TipoNota, TipoPublicacao,
TipoVide, VeiculoPublicacao)
from norma.models import NormaJuridica
from sapl.crud import build_crud
@ -49,6 +53,13 @@ tipo_publicacao_crud = build_crud(
[('sigla', 2), ('nome', 10)]],
])
perfil_estr_txt_norm = build_crud(
PerfilEstruturalTextosNormativos, 'perfil_estrutural', [
[_('Perfil Estrutural de Textos Normativos'),
[('sigla', 2), ('nome', 10)]],
])
veiculo_publicacao_crud = build_crud(
VeiculoPublicacao, 'veiculo_publicacao', [
@ -97,10 +108,6 @@ tipo_dispositivo_crud = build_crud(
],
[_('Outras Configurações'),
[('quantidade_permitida', 12),
],
],
])
@ -246,7 +253,20 @@ class DispositivoView(CompilacaoView):
return itens
class CompilacaoEditView(CompilacaoView):
class UpLoadImportFileForm(forms.Form):
import_file = forms.FileField(
required=True,
label=_('Arquivo formato ODF para Importanção'))
def handle_uploaded_file(f, outfilepath):
with open(outfilepath, 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
class CompilacaoEditView(CompilacaoView, FormMixin):
template_name = 'compilacao/edit.html'
flag_alteradora = -1
@ -254,11 +274,60 @@ class CompilacaoEditView(CompilacaoView):
flag_nivel_ini = 0
flag_nivel_old = -1
pk_add = 0
pk_edit = 0
pk_view = 0
def post(self, request, *args, **kwargs):
form = UpLoadImportFileForm(request.POST, request.FILES)
message = "Arquivo Submetido com sucesso"
self.object_list = self.get_queryset()
if form.is_valid():
try:
f = request.FILES['import_file']
outfilepath = '/tmp/' + f.name
handle_uploaded_file(f, outfilepath)
p = Parser()
p.parser(outfilepath)
except Exception as e:
print(e)
context = self.get_context_data(
object_list=self.object_list,
form=form,
message=message,
view=self,
parser_list=p.parser_list)
return render(request, self.template_name, context)
else:
context = self.get_context_data(
object_list=self.object_list,
form=form,
message=form.errors,
view=self)
return self.form_invalid(context)
return self.render_to_response({'form': form})
def form_invalid(self, context):
return self.render_to_response(context)
def get(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
form_class = UpLoadImportFileForm
self.form = self.get_form(form_class)
context = self.get_context_data(
object_list=self.object_list,
form=self.form)
return self.render_to_response(context)
def get_queryset(self):
self.pk_add = 0
self.pk_edit = 0
self.pk_view = 0
self.flag_alteradora = -1
@ -315,8 +384,25 @@ class CompilacaoEditView(CompilacaoView):
return result
def set_perfil_in_session(self, request=None, perfil_id=0):
if not request:
return None
class DispositivoEditView(CompilacaoEditView, FormMixin):
if perfil_id:
perfil = PerfilEstruturalTextosNormativos.objects.get(
pk=perfil_id)
request.session['perfil_estrutural'] = perfil.pk
else:
perfis = PerfilEstruturalTextosNormativos.objects.filter(
padrao=True)[:1]
if not perfis.exists():
request.session.pop('perfil_estrutural')
else:
request.session['perfil_estrutural'] = perfis[0].pk
class DispositivoEditView(CompilacaoEditView):
template_name = 'compilacao/edit_bloco.html'
def post(self, request, *args, **kwargs):
@ -357,19 +443,45 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
return JsonResponse(data, safe=False)
def get_queryset_perfil_estrutural(self):
perfis = PerfilEstruturalTextosNormativos.objects.all()
return perfis
def get(self, request, *args, **kwargs):
try:
if 'perfil_pk' in request.GET:
self.set_perfil_in_session(
request, request.GET['perfil_pk'])
elif 'perfil_estrutural' not in request.session:
self.set_perfil_in_session(request=request)
self.object_list = self.get_queryset()
self.perfil_estrutural_list = self.get_queryset_perfil_estrutural()
context = self.get_context_data(
object_list=self.object_list,
perfil_estrutural_list=self.perfil_estrutural_list
)
except Exception as e:
print(e)
return self.render_to_response(context)
def get_queryset(self):
self.flag_alteradora = -1
self.flag_nivel_ini = 0
self.flag_nivel_old = -1
try:
self.pk_add = int(self.request.GET['pkadd'])
self.pk_edit = int(self.request.GET['edit'])
except:
self.pk_add = 0
self.pk_edit = 0
self.pk_view = int(self.kwargs['dispositivo_id'])
try:
if self.pk_add == self.pk_view:
if self.pk_edit == self.pk_view:
bloco = Dispositivo.objects.get(
pk=self.kwargs['dispositivo_id'])
else:
@ -381,7 +493,7 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
self.flag_nivel_old = bloco.nivel - 1
self.flag_nivel_ini = bloco.nivel
if self.pk_add == self.pk_view:
if self.pk_edit == self.pk_view:
return [bloco, ]
proximo_bloco = Dispositivo.objects.filter(
@ -402,14 +514,20 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
).select_related(*DISPOSITIVO_SELECT_RELATED)
return itens
def select_provaveis_inserts(self):
def select_provaveis_inserts(self, request=None):
try:
if request and 'perfil_estrutural' not in request.session:
self.set_perfil_in_session(request)
perfil_pk = request.session['perfil_estrutural']
# Não salvar d_base
if self.pk_add == 0:
if self.pk_edit == 0:
base = Dispositivo.objects.get(pk=self.pk_view)
else:
base = Dispositivo.objects.get(pk=self.pk_add)
base = Dispositivo.objects.get(pk=self.pk_edit)
prox_possivel = Dispositivo.objects.filter(
ordem__gt=base.ordem,
@ -444,14 +562,15 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
if dp.nivel >= nivel:
continue
if dp.is_relative_auto_insert():
if dp.is_relative_auto_insert(perfil_pk):
continue
if prox_possivel and \
dp.tipo_dispositivo != base.tipo_dispositivo and\
dp.nivel < prox_possivel.nivel and\
not prox_possivel.tipo_dispositivo.permitido_inserir_in(
dp.tipo_dispositivo):
dp.tipo_dispositivo,
perfil_pk=perfil_pk):
if dp.tipo_dispositivo != prox_possivel.tipo_dispositivo:
continue
@ -469,6 +588,13 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
dp.tipo_dispositivo.nome,),
'dispositivo_base': base.pk})
if dp.dispositivo_pai:
flag_pv = dp.tipo_dispositivo.permitido_variacao(
dp.dispositivo_pai.tipo_dispositivo,
perfil_pk=perfil_pk)
else:
flag_pv = False
r = []
flag_direcao = 1
flag_variacao = 0
@ -491,8 +617,12 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
'dispositivo_base': base.pk})
flag_direcao = -1
r.reverse()
if not flag_pv:
r = [r[0], ]
if len(r) > 0 and dp.tipo_dispositivo.formato_variacao0 == \
TipoDispositivo.FNCN:
r = [r[0], ]
@ -530,7 +660,9 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
for td in otds:
if paradentro and not td.permitido_inserir_in(
tipb, excluir_autos=True):
tipb,
include_relative_autos=False,
perfil_pk=perfil_pk):
continue
base.tipo_dispositivo = td
@ -541,28 +673,31 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
for possivelpai in parents:
if td.permitido_inserir_in(
possivelpai.tipo_dispositivo,
excluir_autos=True):
include_relative_autos=False,
perfil_pk=perfil_pk):
flag_insercao = True
break
if not flag_insercao:
continue
if possivelpai.is_relative_auto_insert():
if possivelpai.is_relative_auto_insert(perfil_pk):
continue
if prox_possivel:
if prox_possivel.nivel == base.nivel:
if prox_possivel.tipo_dispositivo != td and\
not prox_possivel.tipo_dispositivo.\
permitido_inserir_in(td):
permitido_inserir_in(
td, perfil_pk=perfil_pk):
continue
else:
if possivelpai.tipo_dispositivo != \
prox_possivel.tipo_dispositivo and\
not prox_possivel.tipo_dispositivo.\
permitido_inserir_in(
possivelpai.tipo_dispositivo) and \
possivelpai.tipo_dispositivo,
perfil_pk=perfil_pk) and \
possivelpai.nivel < \
prox_possivel.nivel:
continue
@ -610,17 +745,33 @@ class ActionsEditMixin(object):
def render_to_json_response(self, context, **response_kwargs):
if context['action'] == 'add_next':
return JsonResponse(self.add_next(context), safe=False)
elif context['action'] == 'add_in':
return JsonResponse(self.add_in(context), safe=False)
elif context['action'] == 'add_prior':
return JsonResponse(self.add_prior(context), safe=False)
test = getattr(self, context['action'])
return JsonResponse(test(context), safe=False)
def delete_item_dispositivo(self, context):
return self.delete_bloco_dispositivo(context)
def delete_bloco_dispositivo(self, context):
base = Dispositivo.objects.get(pk=context['dispositivo_id'])
base_anterior = Dispositivo.objects.order_by('-ordem').filter(
norma_id=base.norma_id,
ordem__lt=base.ordem
)[:1]
base.delete()
if base_anterior.exists():
if base_anterior[0].dispositivo_pai_id:
data = {'pk': base_anterior[0].pk, 'pai': [
base_anterior[0].dispositivo_pai_id, ]}
else:
return JsonResponse({}, safe=False)
data = {'pk': base_anterior[0].pk, 'pai': [-1, ]}
return data
else:
return {}
def add_prior(self, context):
pass
return {}
def add_in(self, context):
return self.add_next(context, local_add='add_in')
@ -637,7 +788,7 @@ class ActionsEditMixin(object):
count_auto_insert = 0
for tipoauto in tipos_dp_auto_insert:
qtdp = tipoauto.filho_permitido.quantidade_permitida
qtdp = tipoauto.quantidade_permitida
if qtdp >= 0:
qtdp -= Dispositivo.objects.filter(
norma_id=base.norma_id,
@ -657,7 +808,9 @@ class ActionsEditMixin(object):
if dp.tipo_dispositivo == tipo:
dp_irmao = dp
break
if tipo.permitido_inserir_in(dp.tipo_dispositivo):
if tipo.permitido_inserir_in(
dp.tipo_dispositivo,
perfil_pk=context['perfil_pk']):
dp_pai = dp
break
dp_pai = dp
@ -723,12 +876,14 @@ class ActionsEditMixin(object):
antes da inserção atual e que são inferiores a dp,
redirecionando para o novo pai'''
nivel = sys.maxsize
flag_niveis = False
if not dp.tipo_dispositivo.dispositivo_de_alteracao:
possiveis_filhos = Dispositivo.objects.filter(
ordem__gt=dp.ordem,
norma_id=dp.norma_id)
nivel = sys.maxsize
flag_niveis = False
for filho in possiveis_filhos:
if filho.nivel > nivel:
@ -740,7 +895,8 @@ class ActionsEditMixin(object):
nivel = filho.nivel
if not filho.tipo_dispositivo.permitido_inserir_in(
dp.tipo_dispositivo):
dp.tipo_dispositivo,
perfil_pk=context['perfil_pk']):
continue
filho.dispositivo_pai = dp
@ -795,7 +951,7 @@ class ActionsEditMixin(object):
contagem continua, caso a inserção seja uma articulação'''
numtipos = {}
if tipo.class_css == 'articulacao':
if dp.nivel == 0:
proxima_articulacao = Dispositivo.objects.filter(
ordem__gt=dp.ordem,
@ -894,6 +1050,14 @@ class ActionsEditView(ActionsEditMixin, TemplateView):
def render_to_response(self, context, **response_kwargs):
context['action'] = self.request.GET['action']
if 'tipo_pk' in self.request.GET:
context['tipo_pk'] = self.request.GET['tipo_pk']
if 'variacao' in self.request.GET:
context['variacao'] = self.request.GET['variacao']
if 'perfil_estrutural' in self.request.session:
context['perfil_pk'] = self.request.session['perfil_estrutural']
return self.render_to_json_response(context, **response_kwargs)

1
requirements/requirements.txt

@ -9,6 +9,7 @@ django-crispy-forms
django-extra-views
django-vanilla-views
git+git://github.com/interlegis/django-sass-processor.git
git+git://github.com/LeandroRoberto/odfpy.git
libsass
psycopg2
pytz

35
static/js/compilacao.js

@ -63,12 +63,14 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action,
var _action = __action;
var _variacao = '';
var _tipo_pk = '';
var _perfil_pk = '';
if (event != null) {
pk_refresh = event.currentTarget.getAttribute('pk');
_action = $(this).attr('action');
_variacao = $(this).attr('variacao');
_tipo_pk = $(this).attr('tipo_pk');
_perfil_pk = $(this).attr('perfil_pk');
}
if (pk_edit == null)
@ -78,20 +80,22 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action,
if (_action == '')
return;
else if ( _action == null) {
url = pk_refresh+'/refresh?pkadd='+pk_edit;
url = pk_refresh+'/refresh?edit='+pk_edit;
}
else if (_action.startsWith('refresh')) {
var str = _action.split(':');
if (str.length > 1) {
if(_action.endsWith('perfil')) {
url = '&perfil_pk='+_perfil_pk;
}
else {
editortype = str[1];
SetCookie("editortype", editortype, 30)
}
url = pk_refresh+'/refresh?pkadd='+pk_edit+url;
$("#message_block").css("display", "block");
}
else {
url = pk_refresh+'/refresh?edit='+pk_edit+url;
}
else if (_action.startsWith('add_')) {
url = pk_refresh+'/actions?action='+_action;
url += '&tipo_pk='+_tipo_pk;
@ -100,11 +104,14 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action,
$("#message_block").css("display", "block");
}
else if (_action.startsWith('delete_')) {
url = pk_refresh+'/actions?action='+_action;
$("#message_block").css("display", "block");
}
$.get(url).done(function( data ) {
if ( _action == null || _action.startsWith('refresh')) {
if (flag_refresh_all) {
if (flag_actions_vibible)
clearEditSelected();
@ -165,6 +172,16 @@ var clickUpdateDispositivo = function(event, __pk_refresh, __pk_edit, __action,
alert('Erro na inserção!');
}
}
else if (_action.startsWith('delete_')) {
$("#message_block").css("display", "block");
clearEditSelected();
if (data.pk != null) {
refreshScreenFocusPk(data);
}
else {
alert('Erro exclusão!');
}
}
else {
clearEditSelected();
reloadFunctionClicks();
@ -196,11 +213,11 @@ function clearEditSelected() {
}
function reloadFunctionClicks() {
$('.dpt .de, .btn-action, .btn-inserts, .btn-edit').off();
$('.dpt .de, .btn-action, .btn-edit').off();
$('.dpt .de, .btn-edit').on('click', clickEditDispositivo);
$('.btn-action, .btn-inserts').on('click', clickUpdateDispositivo);
$('.btn-action').on('click', clickUpdateDispositivo);
$('#editdi_texto').focus();
}

92
static/styles/compilacao.scss

@ -17,6 +17,7 @@ $color_actions_border: #CCC;
border-radius: $radius;
}
@mixin li_flutuante() {
& > ul {
@ -34,7 +35,9 @@ $color_actions_border: #CCC;
a {
border-right: 0px !important;
}
}
&:first-child {
&::before {
border-width: 0.375rem;
@ -48,6 +51,11 @@ $color_actions_border: #CCC;
top: -0.75rem;
left: 0.9375rem;
}
&:hover::before {
border-color: transparent transparent #0A5EA4;
}
}
}
// This bridges the gap between the top bar and a dropdown.
&::after {
content: "";
@ -74,7 +82,9 @@ $color_actions_border: #CCC;
}
}
.test_import:nth-child(even) {
background-color: #ccc;
}
#message_block {
display: block;
position: fixed;
@ -267,7 +277,31 @@ $color_actions_border: #CCC;
}
.fixed{
z-index:98;
opacity: 0.2;
transition: all 2s ease-in-out;
-webkit-transition-delay: 3s; /* Safari */
transition-delay: 3s;
&:hover {
-webkit-transition-delay: 0s; /* Safari */
transition-delay: 0s;
transition: all 0.3s ease-in-out;
opacity: 0.9;
&::-webkit-scrollbar {
width: 10px;
height: 10px;
}
&::-webkit-scrollbar-thumb:vertical {
height: 30px;
background-color: rgba(0, 0, 0, 0.1);
}
}
}
} /* end cp */
@ -297,7 +331,7 @@ $color_actions_border: #CCC;
& > .actions_left {
color: #fff;
position: absolute;
left: -2em;
left: -2.6em;
opacity: 0;
transition: all 0.4s ease-in-out;
a {
@ -360,13 +394,10 @@ $color_actions_border: #CCC;
@extend .articulacao;
margin: 0;
padding-top: 3em;
padding-left: 0em;
background: #ddd;
&::before {
content: "Bloco de Alteração";
position:absolute;
left: 0;
right: 0;
top: 0;
display: block;
}
@ -407,11 +438,6 @@ $color_actions_border: #CCC;
}
.bloco_alteracao {
&::before {
display: none;
}
}
& > .bloco {
padding: 1em 0;
@ -466,7 +492,6 @@ $color_actions_border: #CCC;
& > a {
text-shadow: 0 0 5px #777;
color: #ff0;
font-weight: bold;
}
}
}
@ -661,14 +686,16 @@ $color_actions_border: #CCC;
}
&.add_prior {
@include li_flutuante();
display: block;
table-layout: fixed;
}
&.opc_excluir {
@include li_flutuante();
display: block;
table-layout: fixed;
position: static;
& > ul {
right: 0.5em;
li {
a {
background-color: #A70808;
@ -676,10 +703,16 @@ $color_actions_border: #CCC;
background: #c70808;
}
}
}
&:first-child {
&::before {
border-color: transparent transparent #A70808;
right: 10%;
left: auto;
}
&:hover::before {
border-color: transparent transparent #c70808;
}
}
}
}
@ -692,6 +725,21 @@ $color_actions_border: #CCC;
.menu_flutuante {
& > li {
@include li_flutuante();
&.opc_excluir {
& > ul {
li {
&:first-child {
&::before {
right: auto;
left: 0.9375rem;
}
}
}
}
}
}
}
@ -803,7 +851,7 @@ $color_actions_border: #CCC;
left: 1em !important;
right: 1em !important;
margin-left: 0;
&::before {
li:first-child::before {
left: 37%;
}
}
@ -816,18 +864,18 @@ $color_actions_border: #CCC;
right: 0 !important;
margin-left: 0;
margin-right: 0.5em;
&::before {
li:first-child::before {
right: 42%;
left: auto;
}
}
&.opc_excluir > ul {
left: 30% !important;
left: 10% !important;
right: 0 !important;
margin-left: 0;
margin-right: 0.5em;
&::before {
right: 35%;
li:first-child::before {
right: 27%;
left: auto;
}
}

31
templates/compilacao/edit.html

@ -3,6 +3,8 @@
{% load compilacao_filters %}
{% load staticfiles %}
{% load sass_tags %}
{% load crispy_forms_tags %}
{% block head_content %}{{block.super}}
<link rel="stylesheet" href="{% sass_src 'styles/compilacao.scss' %}" type="text/css">
@ -22,4 +24,33 @@
{% include 'compilacao/edit_bloco.html'%}
</div>
{% if user.is_authenticated and False %}
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{% if message %}
<div data-alert="" class="alert-box success radius">
{{message}}
<a href="#" class="close">×</a>
</div>
{% endif %}
<fieldset>
<legend>{% trans 'Parser ODF' %}</legend>
{{ form.as_p }}
<input type="submit" name="import_submit" value="{% trans 'Importar' %}" class="button primary" />
</fieldset>
</form>
{% for parser in parser_list %}
<div class="test_import">
{{ parser|safe}}
</div>
{% endfor %}
{% endif%}
{% endblock base_content %}

36
templates/compilacao/edit_bloco.html

@ -35,40 +35,40 @@
</ul>
<ul class="btns-action actions_left">
<li><a class="btn-left btn-action" pk="{{dpt.pk}}" title="Button Left">BL</a></li>
<li><a class="btn-left btn-action" pk="{{dpt.pk}}" title="Button Left">BL</a></li>
<li><a class="btn-left btn-action" pk="{{dpt.pk}}" title="TODO: Notas...">Nt</a></li>
<li><a class="btn-left btn-action" pk="{{dpt.pk}}" title="TODO: Vides...">Vd</a></li>
</ul>
<ul class="btns-action actions_bottom">
<li><a class="btn-bottom btn-action" pk="{{dpt.pk}}" title="Button Bottom">BB</a></li>
<li><a class="btn-bottom btn-action" pk="{{dpt.pk}}" title="Button Bottom">BB</a></li>
{% for perfil in perfil_estrutural_list%}
<li class="{%if request.session.perfil_estrutural == perfil.pk%}selected{%endif%}"><a class="btn-bottom btn-action" pk="{{dpt.pk}}" perfil_pk="{{perfil.pk}}" action="refresh:perfil" title="{{perfil.nome}}">{{perfil.sigla}}</a></li>
{% endfor %}
</ul>
<ul class="actions_inserts {% if not dpt.tipo_dispositivo.dispositivo_de_articulacao %}menu_flutuante{%endif%}">
{% if dpt.dispositivo_subsequente == None %}
{% for inserts in view.select_provaveis_inserts%}
{% for inserts in view|select_provaveis_inserts:request %}
<li class="{{inserts|get_field:'action'}}"><a class="btn-inserts" action="" pk="{{dpt.pk}}">{{inserts|get_field:'icone'|safe}}<span>{{inserts|get_field:'tipo_insert'}}</span></a>
<ul id="afe{{dpt.id}}" >
{% for item in inserts|get_field:'itens' %}
<li><a class="btn-inserts" action="{{inserts|get_field:'action'}}" pk="{{item|get_field:'dispositivo_base'}}" variacao="{{item|get_field:'variacao'}}" tipo_pk="{{item|get_field:'tipo_pk'}}">{{item|get_field:'provavel'}}</a></li>
<li><a class="btn-inserts btn-action" action="{{inserts|get_field:'action'}}" pk="{{item|get_field:'dispositivo_base'}}" variacao="{{item|get_field:'variacao'}}" tipo_pk="{{item|get_field:'tipo_pk'}}">{{item|get_field:'provavel'}}</a></li>
{% endfor %}
</ul>
</li>
{% endfor %}
{%endif%}
<li class="opc_excluir"><a class="btn-excluir">&nbsp;<span>Excluir</span></a>
{% if not dpt|is_relative_auto_insert:request %}
<li class="opc_excluir"><a {% if not dpt.dispositivos_filhos_set.exists %}class="btn-excluir btn-action" action="delete_item_dispositivo" pk={{dpt.pk}}{%else%}class="btn-excluir"{%endif%}>&nbsp;<span>Excluir</span></a>
{% if dpt.dispositivos_filhos_set.exists %}
<ul>
<li><a href="#" class="btn-excluir">&nbsp;<span>Excluir apenas este dispositivo</span></a></li>
<li><a href="#" class="btn-excluir">&nbsp;<span>Excluir toda a estrutura deste dispositivo</span></a></li>
<li><a href="#" class="btn-excluir btn-action" action="delete_item_dispositivo" pk={{dpt.pk}}>TODO: Excluir apenas este dispositivo</a></li>
<li><a href="#" class="btn-excluir btn-action" action="delete_bloco_dispositivo" pk={{dpt.pk}}>TODO: Excluir toda a estrutura deste dispositivo</a></li>
</ul>
{% endif %}
</li>
{% endif %}
<li><a onclick="onSubmitEditForm()" class="btn-salvar">&nbsp<span>Salvar</span></a></li>
</ul>
@ -97,11 +97,13 @@
</div>
{% endif%}
{% if view.pk_view == 0 and view.pk_add == 0 or view.pk_add != view.pk_view %}
{% if view.pk_view == 0 and view.pk_edit == 0 or view.pk_edit != view.pk_view %}
{% if not dpt.rotulo and not dpt.texto %}
<div class="btns-action actions_left">
<a class="btn-edit" pk="{{dpt.pk}}" title="Edição do dispositivo: {{ dpt.tipo_dispositivo.nome }} {{ dpt.rotulo }}">E</a>
</div>
{% endif %}
<div class="bloco {% dispositivo_desativado dpt view.inicio_vigencia view.fim_vigencia %} {{ dpt.tipo_dispositivo.class_css }}">
{% spaceless %}
<a class="de" id="id{{dpt.id}}" pk="{{dpt.pk}}" ordem="{{dpt.ordem}}" name="{{dpt.pk}}" title="{{dpt.pk}}">{{ dpt.tipo_dispositivo.rotulo_prefixo_html|safe }}{{ dpt.rotulo }}{{ dpt.tipo_dispositivo.rotulo_sufixo_html|safe }}{{ dpt.tipo_dispositivo.texto_prefixo_html|safe }}{% if dpt.texto == '' and not dpt.tipo_dispositivo.dispositivo_de_articulacao %}<span class="semtexto">({{dpt.tipo_dispositivo}} sem texto)</span>{%else%}{{ dpt.texto|safe }}{%endif%}</a>

5
templates/compilacao/index.html

@ -6,7 +6,6 @@
{% block head_content %}{{block.super}}
<link rel="stylesheet" href="{% sass_src 'styles/compilacao.scss' %}" type="text/css">
<script type="text/javascript" src="{% static 'js/compilacao.js' %}"></script>
{% endblock %}
@ -29,11 +28,13 @@ $(window).load(function() {
setTimeout(function() {
height = $( "section.vigencias" ).height();
$('html, body').animate({
scrollTop: window.pageYOffset - height - 37
scrollTop: window.pageYOffset - height - 55
}, 300);
}, 100);
});
function textoMultiVigente(item) {
$(".cp .tipo-vigencias a").removeClass("selected")
$(item).addClass("selected")

1
templates/sistema.html

@ -85,6 +85,7 @@
<li><a href="{% url 'tipovide:list' %}">Tipo de Vide</a></li>
<li><a href="{% url 'tipopublicacao:list' %}">Tipo de Publicação</a></li>
<li><a href="{% url 'veiculopublicacao:list' %}">Veículo de Públicação</a></li>
<li><a href="{% url 'perfilestruturaltextosnormativos:list' %}">Perfil Estrutural de Textos Normativos</a></li>
</ul>
<h5>Módulo Sessão Plenária</h5>

Loading…
Cancel
Save