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. 18
      compilacao/templatetags/compilacao_filters.py
  11. 8
      compilacao/urls.py
  12. 274
      compilacao/views.py
  13. 1
      requirements/requirements.txt
  14. 39
      static/js/compilacao.js
  15. 118
      static/styles/compilacao.scss
  16. 31
      templates/compilacao/edit.html
  17. 46
      templates/compilacao/edit_bloco.html
  18. 5
      templates/compilacao/index.html
  19. 3
      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 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 BaseModel(models.Model):
class Meta: class Meta:
@ -77,12 +88,6 @@ class TipoVide(models.Model):
class TipoDispositivo(BaseModel): 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 - 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 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 ';' 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, choices=YES_NO_CHOICES,
default=False, default=False,
verbose_name=_('Dispositivo de Articulação (Sem Texto)')) 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( formato_variacao0 = models.CharField(
max_length=1, max_length=1,
choices=FORMATO_NUMERACAO_CHOICES, choices=FORMATO_NUMERACAO_CHOICES,
@ -238,10 +247,6 @@ class TipoDispositivo(BaseModel):
symmetrical=False, symmetrical=False,
related_name='+') related_name='+')
quantidade_permitida = models.IntegerField(
default=-1,
verbose_name=_('Quantidade permitida dentro de uma Norma'))
class Meta: class Meta:
verbose_name = _('Tipo de Dispositivo') verbose_name = _('Tipo de Dispositivo')
verbose_name_plural = _('Tipos de Dispositivo') verbose_name_plural = _('Tipos de Dispositivo')
@ -250,32 +255,86 @@ class TipoDispositivo(BaseModel):
def __str__(self): def __str__(self):
return self.nome return self.nome
def permitido_inserir_in(self, base, excluir_autos=False): def permitido_inserir_in(
pp = self.possiveis_pais.filter(pai=base) 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 pp.exists():
if excluir_autos: if not include_relative_autos:
if pp[0].filho_de_insercao_automatica: if pp[0].filho_de_insercao_automatica:
return False return False
return True return True
return False 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): class TipoDispositivoRelationship(BaseModel):
pai = models.ForeignKey(TipoDispositivo, related_name='filhos_permitidos') pai = models.ForeignKey(TipoDispositivo, related_name='filhos_permitidos')
filho_permitido = models.ForeignKey( filho_permitido = models.ForeignKey(
TipoDispositivo, TipoDispositivo,
blank=True, null=True, default=None,
related_name='possiveis_pais') related_name='possiveis_pais')
perfil = models.ForeignKey(PerfilEstruturalTextosNormativos)
filho_de_insercao_automatica = models.BooleanField( filho_de_insercao_automatica = models.BooleanField(
default=False, default=False,
choices=YES_NO_CHOICES, verbose_name=_('Filho de Inserção Automática')) 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: class Meta:
verbose_name = _('Relação Direta Permitida') verbose_name = _('Relação Direta Permitida')
verbose_name_plural = _('Relaçõe Diretas Permitidas') verbose_name_plural = _('Relaçõe Diretas Permitidas')
ordering = ['pai', 'filho_permitido'] ordering = ['pai', 'filho_permitido']
unique_together = ( unique_together = (
('pai', 'filho_permitido',),) ('pai', 'filho_permitido', 'perfil'),)
def __str__(self): def __str__(self):
return '%s - %s' % ( return '%s - %s' % (
@ -331,7 +390,7 @@ class Publicacao(models.Model):
return '%s: %s' % (self.veiculo_publicacao, self.publicacao) return '%s: %s' % (self.veiculo_publicacao, self.publicacao)
class Dispositivo(BaseModel): class Dispositivo(BaseModel, TimestampedMixin):
TEXTO_PADRAO_DISPOSITIVO_REVOGADO = _('(Revogado)') TEXTO_PADRAO_DISPOSITIVO_REVOGADO = _('(Revogado)')
INTERVALO_ORDEM = 1000 INTERVALO_ORDEM = 1000
ordem = models.PositiveIntegerField( ordem = models.PositiveIntegerField(
@ -411,8 +470,6 @@ class Dispositivo(BaseModel):
choices=YES_NO_CHOICES, choices=YES_NO_CHOICES,
verbose_name=_('Visibilidade na Norma Publicada')) verbose_name=_('Visibilidade na Norma Publicada'))
timestamp = models.DateTimeField()
tipo_dispositivo = models.ForeignKey( tipo_dispositivo = models.ForeignKey(
TipoDispositivo, TipoDispositivo,
related_name='dispositivos_do_tipo_set', related_name='dispositivos_do_tipo_set',
@ -894,11 +951,12 @@ class Dispositivo(BaseModel):
return proxima_articulacao[0] 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: if self.dispositivo_pai is not None:
# pp possiveis_pais # pp possiveis_pais
pp = self.tipo_dispositivo.possiveis_pais.filter( 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.exists():
if pp[0].filho_de_insercao_automatica: if pp[0].filho_de_insercao_automatica:

18
compilacao/templatetags/compilacao_filters.py

@ -46,6 +46,8 @@ def nota_automatica(dispositivo):
d = dispositivo.dispositivo_atualizador.dispositivo_pai d = dispositivo.dispositivo_atualizador.dispositivo_pai
if dispositivo.texto == Dispositivo.TEXTO_PADRAO_DISPOSITIVO_REVOGADO: if dispositivo.texto == Dispositivo.TEXTO_PADRAO_DISPOSITIVO_REVOGADO:
return 'Revogado pelo %s.' % d return 'Revogado pelo %s.' % d
elif not dispositivo.dispositivo_substituido:
return 'Inclusão feita pelo %s.' % d
else: else:
return 'Alteração feita pelo %s.' % d return 'Alteração feita pelo %s.' % d
return '' return ''
@ -69,6 +71,16 @@ def get_sign_vigencia(value):
return signer.sign(str(string)) 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 @register.filter
def isinst(value, class_str): def isinst(value, class_str):
classe = value.__class__.__name__ classe = value.__class__.__name__
@ -82,11 +94,11 @@ def render_actions_head(view, d_atual):
return False return False
# Menu # 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 return True
# conteudo e menu no filho # 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 True
return False return False
@ -95,7 +107,7 @@ def render_actions_head(view, d_atual):
@register.filter @register.filter
def short_string(str, length): def short_string(str, length):
if len(str) > length: if len(str) > length:
return str[:length]+'...' return str[:length] + '...'
else: else:
return str return str

8
compilacao/urls.py

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

274
compilacao/views.py

@ -2,17 +2,21 @@ from collections import OrderedDict
from datetime import datetime, timedelta from datetime import datetime, timedelta
from os.path import sys from os.path import sys
from django import forms
from django.core.signing import Signer from django.core.signing import Signer
from django.db.models import Q from django.db.models import Q
from django.http.response import JsonResponse from django.http.response import JsonResponse
from django.shortcuts import render
from django.utils.dateparse import parse_date from django.utils.dateparse import parse_date
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.views.generic.edit import FormMixin from django.views.generic.edit import FormMixin
from django.views.generic.list import ListView from django.views.generic.list import ListView
from compilacao.models import (Dispositivo, TipoDispositivo, TipoNota, from compilacao.file2dispositivo import Parser
TipoPublicacao, TipoVide, VeiculoPublicacao) from compilacao.models import (Dispositivo, PerfilEstruturalTextosNormativos,
TipoDispositivo, TipoNota, TipoPublicacao,
TipoVide, VeiculoPublicacao)
from norma.models import NormaJuridica from norma.models import NormaJuridica
from sapl.crud import build_crud from sapl.crud import build_crud
@ -49,6 +53,13 @@ tipo_publicacao_crud = build_crud(
[('sigla', 2), ('nome', 10)]], [('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( veiculo_publicacao_crud = build_crud(
VeiculoPublicacao, 'veiculo_publicacao', [ 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 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' template_name = 'compilacao/edit.html'
flag_alteradora = -1 flag_alteradora = -1
@ -254,11 +274,60 @@ class CompilacaoEditView(CompilacaoView):
flag_nivel_ini = 0 flag_nivel_ini = 0
flag_nivel_old = -1 flag_nivel_old = -1
pk_add = 0 pk_edit = 0
pk_view = 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): def get_queryset(self):
self.pk_add = 0 self.pk_edit = 0
self.pk_view = 0 self.pk_view = 0
self.flag_alteradora = -1 self.flag_alteradora = -1
@ -315,8 +384,25 @@ class CompilacaoEditView(CompilacaoView):
return result return result
def set_perfil_in_session(self, request=None, perfil_id=0):
if not request:
return None
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, FormMixin):
class DispositivoEditView(CompilacaoEditView):
template_name = 'compilacao/edit_bloco.html' template_name = 'compilacao/edit_bloco.html'
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
@ -357,19 +443,45 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
return JsonResponse(data, safe=False) 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): def get_queryset(self):
self.flag_alteradora = -1 self.flag_alteradora = -1
self.flag_nivel_ini = 0 self.flag_nivel_ini = 0
self.flag_nivel_old = -1 self.flag_nivel_old = -1
try: try:
self.pk_add = int(self.request.GET['pkadd']) self.pk_edit = int(self.request.GET['edit'])
except: except:
self.pk_add = 0 self.pk_edit = 0
self.pk_view = int(self.kwargs['dispositivo_id']) self.pk_view = int(self.kwargs['dispositivo_id'])
try: try:
if self.pk_add == self.pk_view: if self.pk_edit == self.pk_view:
bloco = Dispositivo.objects.get( bloco = Dispositivo.objects.get(
pk=self.kwargs['dispositivo_id']) pk=self.kwargs['dispositivo_id'])
else: else:
@ -381,7 +493,7 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
self.flag_nivel_old = bloco.nivel - 1 self.flag_nivel_old = bloco.nivel - 1
self.flag_nivel_ini = bloco.nivel self.flag_nivel_ini = bloco.nivel
if self.pk_add == self.pk_view: if self.pk_edit == self.pk_view:
return [bloco, ] return [bloco, ]
proximo_bloco = Dispositivo.objects.filter( proximo_bloco = Dispositivo.objects.filter(
@ -402,14 +514,20 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
).select_related(*DISPOSITIVO_SELECT_RELATED) ).select_related(*DISPOSITIVO_SELECT_RELATED)
return itens return itens
def select_provaveis_inserts(self): def select_provaveis_inserts(self, request=None):
try: 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 # Não salvar d_base
if self.pk_add == 0: if self.pk_edit == 0:
base = Dispositivo.objects.get(pk=self.pk_view) base = Dispositivo.objects.get(pk=self.pk_view)
else: else:
base = Dispositivo.objects.get(pk=self.pk_add) base = Dispositivo.objects.get(pk=self.pk_edit)
prox_possivel = Dispositivo.objects.filter( prox_possivel = Dispositivo.objects.filter(
ordem__gt=base.ordem, ordem__gt=base.ordem,
@ -444,14 +562,15 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
if dp.nivel >= nivel: if dp.nivel >= nivel:
continue continue
if dp.is_relative_auto_insert(): if dp.is_relative_auto_insert(perfil_pk):
continue continue
if prox_possivel and \ if prox_possivel and \
dp.tipo_dispositivo != base.tipo_dispositivo and\ dp.tipo_dispositivo != base.tipo_dispositivo and\
dp.nivel < prox_possivel.nivel and\ dp.nivel < prox_possivel.nivel and\
not prox_possivel.tipo_dispositivo.permitido_inserir_in( 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: if dp.tipo_dispositivo != prox_possivel.tipo_dispositivo:
continue continue
@ -469,6 +588,13 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
dp.tipo_dispositivo.nome,), dp.tipo_dispositivo.nome,),
'dispositivo_base': base.pk}) '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 = [] r = []
flag_direcao = 1 flag_direcao = 1
flag_variacao = 0 flag_variacao = 0
@ -491,8 +617,12 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
'dispositivo_base': base.pk}) 'dispositivo_base': base.pk})
flag_direcao = -1 flag_direcao = -1
r.reverse() r.reverse()
if not flag_pv:
r = [r[0], ]
if len(r) > 0 and dp.tipo_dispositivo.formato_variacao0 == \ if len(r) > 0 and dp.tipo_dispositivo.formato_variacao0 == \
TipoDispositivo.FNCN: TipoDispositivo.FNCN:
r = [r[0], ] r = [r[0], ]
@ -530,7 +660,9 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
for td in otds: for td in otds:
if paradentro and not td.permitido_inserir_in( if paradentro and not td.permitido_inserir_in(
tipb, excluir_autos=True): tipb,
include_relative_autos=False,
perfil_pk=perfil_pk):
continue continue
base.tipo_dispositivo = td base.tipo_dispositivo = td
@ -540,29 +672,32 @@ class DispositivoEditView(CompilacaoEditView, FormMixin):
flag_insercao = False flag_insercao = False
for possivelpai in parents: for possivelpai in parents:
if td.permitido_inserir_in( if td.permitido_inserir_in(
possivelpai.tipo_dispositivo, possivelpai.tipo_dispositivo,
excluir_autos=True): include_relative_autos=False,
perfil_pk=perfil_pk):
flag_insercao = True flag_insercao = True
break break
if not flag_insercao: if not flag_insercao:
continue continue
if possivelpai.is_relative_auto_insert(): if possivelpai.is_relative_auto_insert(perfil_pk):
continue continue
if prox_possivel: if prox_possivel:
if prox_possivel.nivel == base.nivel: if prox_possivel.nivel == base.nivel:
if prox_possivel.tipo_dispositivo != td and\ if prox_possivel.tipo_dispositivo != td and\
not prox_possivel.tipo_dispositivo.\ not prox_possivel.tipo_dispositivo.\
permitido_inserir_in(td): permitido_inserir_in(
td, perfil_pk=perfil_pk):
continue continue
else: else:
if possivelpai.tipo_dispositivo != \ if possivelpai.tipo_dispositivo != \
prox_possivel.tipo_dispositivo and\ prox_possivel.tipo_dispositivo and\
not prox_possivel.tipo_dispositivo.\ not prox_possivel.tipo_dispositivo.\
permitido_inserir_in( permitido_inserir_in(
possivelpai.tipo_dispositivo) and \ possivelpai.tipo_dispositivo,
perfil_pk=perfil_pk) and \
possivelpai.nivel < \ possivelpai.nivel < \
prox_possivel.nivel: prox_possivel.nivel:
continue continue
@ -610,17 +745,33 @@ class ActionsEditMixin(object):
def render_to_json_response(self, context, **response_kwargs): def render_to_json_response(self, context, **response_kwargs):
if context['action'] == 'add_next': test = getattr(self, context['action'])
return JsonResponse(self.add_next(context), safe=False) return JsonResponse(test(context), safe=False)
elif context['action'] == 'add_in':
return JsonResponse(self.add_in(context), safe=False) def delete_item_dispositivo(self, context):
elif context['action'] == 'add_prior': return self.delete_bloco_dispositivo(context)
return JsonResponse(self.add_prior(context), safe=False)
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:
data = {'pk': base_anterior[0].pk, 'pai': [-1, ]}
return data
else: else:
return JsonResponse({}, safe=False) return {}
def add_prior(self, context): def add_prior(self, context):
pass return {}
def add_in(self, context): def add_in(self, context):
return self.add_next(context, local_add='add_in') return self.add_next(context, local_add='add_in')
@ -637,7 +788,7 @@ class ActionsEditMixin(object):
count_auto_insert = 0 count_auto_insert = 0
for tipoauto in tipos_dp_auto_insert: for tipoauto in tipos_dp_auto_insert:
qtdp = tipoauto.filho_permitido.quantidade_permitida qtdp = tipoauto.quantidade_permitida
if qtdp >= 0: if qtdp >= 0:
qtdp -= Dispositivo.objects.filter( qtdp -= Dispositivo.objects.filter(
norma_id=base.norma_id, norma_id=base.norma_id,
@ -657,7 +808,9 @@ class ActionsEditMixin(object):
if dp.tipo_dispositivo == tipo: if dp.tipo_dispositivo == tipo:
dp_irmao = dp dp_irmao = dp
break 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 dp_pai = dp
break break
dp_pai = dp dp_pai = dp
@ -723,30 +876,33 @@ class ActionsEditMixin(object):
antes da inserção atual e que são inferiores a dp, antes da inserção atual e que são inferiores a dp,
redirecionando para o novo pai''' redirecionando para o novo pai'''
possiveis_filhos = Dispositivo.objects.filter(
ordem__gt=dp.ordem,
norma_id=dp.norma_id)
nivel = sys.maxsize nivel = sys.maxsize
flag_niveis = False flag_niveis = False
for filho in possiveis_filhos:
if filho.nivel > nivel: if not dp.tipo_dispositivo.dispositivo_de_alteracao:
continue possiveis_filhos = Dispositivo.objects.filter(
ordem__gt=dp.ordem,
norma_id=dp.norma_id)
if filho.dispositivo_pai.ordem >= dp.ordem: for filho in possiveis_filhos:
continue
nivel = filho.nivel if filho.nivel > nivel:
continue
if not filho.tipo_dispositivo.permitido_inserir_in( if filho.dispositivo_pai.ordem >= dp.ordem:
dp.tipo_dispositivo): continue
continue
filho.dispositivo_pai = dp nivel = filho.nivel
filho.clean()
filho.save() if not filho.tipo_dispositivo.permitido_inserir_in(
flag_niveis = True dp.tipo_dispositivo,
perfil_pk=context['perfil_pk']):
continue
filho.dispositivo_pai = dp
filho.clean()
filho.save()
flag_niveis = True
if flag_niveis: if flag_niveis:
dp.organizar_niveis() dp.organizar_niveis()
@ -795,7 +951,7 @@ class ActionsEditMixin(object):
contagem continua, caso a inserção seja uma articulação''' contagem continua, caso a inserção seja uma articulação'''
numtipos = {} numtipos = {}
if tipo.class_css == 'articulacao': if dp.nivel == 0:
proxima_articulacao = Dispositivo.objects.filter( proxima_articulacao = Dispositivo.objects.filter(
ordem__gt=dp.ordem, ordem__gt=dp.ordem,
@ -894,6 +1050,14 @@ class ActionsEditView(ActionsEditMixin, TemplateView):
def render_to_response(self, context, **response_kwargs): def render_to_response(self, context, **response_kwargs):
context['action'] = self.request.GET['action'] context['action'] = self.request.GET['action']
context['tipo_pk'] = self.request.GET['tipo_pk']
context['variacao'] = self.request.GET['variacao'] 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) return self.render_to_json_response(context, **response_kwargs)

1
requirements/requirements.txt

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

39
static/js/compilacao.js

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

118
static/styles/compilacao.scss

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

31
templates/compilacao/edit.html

@ -3,6 +3,8 @@
{% load compilacao_filters %} {% load compilacao_filters %}
{% load staticfiles %} {% load staticfiles %}
{% load sass_tags %} {% load sass_tags %}
{% load crispy_forms_tags %}
{% block head_content %}{{block.super}} {% block head_content %}{{block.super}}
<link rel="stylesheet" href="{% sass_src 'styles/compilacao.scss' %}" type="text/css"> <link rel="stylesheet" href="{% sass_src 'styles/compilacao.scss' %}" type="text/css">
@ -22,4 +24,33 @@
{% include 'compilacao/edit_bloco.html'%} {% include 'compilacao/edit_bloco.html'%}
</div> </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 %} {% endblock base_content %}

46
templates/compilacao/edit_bloco.html

@ -35,40 +35,40 @@
</ul> </ul>
<ul class="btns-action actions_left"> <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="TODO: Notas...">Nt</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: Vides...">Vd</a></li>
</ul> </ul>
<ul class="btns-action actions_bottom">
<ul class="btns-action actions_bottom"> {% for perfil in perfil_estrutural_list%}
<li><a class="btn-bottom btn-action" pk="{{dpt.pk}}" title="Button Bottom">BB</a></li> <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>
<li><a class="btn-bottom btn-action" pk="{{dpt.pk}}" title="Button Bottom">BB</a></li> {% endfor %}
</ul> </ul>
<ul class="actions_inserts {% if not dpt.tipo_dispositivo.dispositivo_de_articulacao %}menu_flutuante{%endif%}"> <ul class="actions_inserts {% if not dpt.tipo_dispositivo.dispositivo_de_articulacao %}menu_flutuante{%endif%}">
{% if dpt.dispositivo_subsequente == None %} {% 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> <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}}" > <ul id="afe{{dpt.id}}" >
{% for item in inserts|get_field:'itens' %} {% 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 %} {% endfor %}
</ul> </ul>
</li> </li>
{% endfor %} {% endfor %}
{%endif%} {%endif%}
<li class="opc_excluir"><a class="btn-excluir">&nbsp;<span>Excluir</span></a>
<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>
</ul>
{% 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 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>
<li><a onclick="onSubmitEditForm()" class="btn-salvar">&nbsp<span>Salvar</span></a></li> <li><a onclick="onSubmitEditForm()" class="btn-salvar">&nbsp<span>Salvar</span></a></li>
</ul> </ul>
@ -97,11 +97,13 @@
</div> </div>
{% endif%} {% 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 %}
<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>
{% 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 }}"> <div class="bloco {% dispositivo_desativado dpt view.inicio_vigencia view.fim_vigencia %} {{ dpt.tipo_dispositivo.class_css }}">
{% spaceless %} {% 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> <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}} {% block head_content %}{{block.super}}
<link rel="stylesheet" href="{% sass_src 'styles/compilacao.scss' %}" type="text/css"> <link rel="stylesheet" href="{% sass_src 'styles/compilacao.scss' %}" type="text/css">
<script type="text/javascript" src="{% static 'js/compilacao.js' %}"></script>
{% endblock %} {% endblock %}
@ -29,11 +28,13 @@ $(window).load(function() {
setTimeout(function() { setTimeout(function() {
height = $( "section.vigencias" ).height(); height = $( "section.vigencias" ).height();
$('html, body').animate({ $('html, body').animate({
scrollTop: window.pageYOffset - height - 37 scrollTop: window.pageYOffset - height - 55
}, 300); }, 300);
}, 100); }, 100);
}); });
function textoMultiVigente(item) { function textoMultiVigente(item) {
$(".cp .tipo-vigencias a").removeClass("selected") $(".cp .tipo-vigencias a").removeClass("selected")
$(item).addClass("selected") $(item).addClass("selected")

3
templates/sistema.html

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

Loading…
Cancel
Save