diff --git a/frontend/src/__apps/compilacao/js/old/compilacao_edit.js b/frontend/src/__apps/compilacao/js/old/compilacao_edit.js
index 63135ab55..13c5aa331 100644
--- a/frontend/src/__apps/compilacao/js/old/compilacao_edit.js
+++ b/frontend/src/__apps/compilacao/js/old/compilacao_edit.js
@@ -228,6 +228,10 @@ window.DispositivoEdit = function () {
dpt.find('.btn-group-inserts').removeClass('open show')
})
+ // Para ativar image_cropping dentro do editor dinâmico descolmentar linha abaixo
+ // e retirar restrição do backend que adiciona input image apenas o editor avançado
+ // window.image_cropping.init()
+
instance.gc()
})
}
diff --git a/frontend/src/__apps/compilacao/js/old/compilacao_view.js b/frontend/src/__apps/compilacao/js/old/compilacao_view.js
index 4dc6a8e74..ef6d495b8 100644
--- a/frontend/src/__apps/compilacao/js/old/compilacao_view.js
+++ b/frontend/src/__apps/compilacao/js/old/compilacao_view.js
@@ -35,6 +35,7 @@ function textoMultiVigente (item, diff) {
_$(item).addClass('active')
_$('.dptt.desativado').removeClass('displaynone')
_$('.desativado > .dn').removeClass('displaynone')
+ _$('.desativado > .dpt-img').removeClass('displaynone')
_$('.dptt.revogado').removeClass('displaynone')
_$('.dtxt').removeClass('displaynone')
_$('.dtxt.diff').remove()
@@ -133,6 +134,7 @@ function textoVigente (item, link) {
_$(item).addClass('active')
_$('.dptt.desativado').addClass('displaynone')
_$('.desativado > .dn').addClass('displaynone')
+ _$('.desativado > .dpt-img').addClass('displaynone')
_$('.nota-alteracao').removeClass('displaynone')
_$('.dptt.revogado').removeClass('displaynone')
if (!link) _$('.nota-alteracao').addClass('displaynone')
diff --git a/frontend/src/__apps/compilacao/scss/compilacao.scss b/frontend/src/__apps/compilacao/scss/compilacao.scss
index a6173399c..668de7383 100644
--- a/frontend/src/__apps/compilacao/scss/compilacao.scss
+++ b/frontend/src/__apps/compilacao/scss/compilacao.scss
@@ -200,7 +200,7 @@ a:link:after, a:visited:after {
margin: -5px auto 0;
border-radius: 50%;
}
-
+
& > a {
position: absolute;
white-space: nowrap;
@@ -219,10 +219,10 @@ a:link:after, a:visited:after {
margin-bottom: 5px;
}
}
-
+
ul {
z-index: 1;
- position: absolute;
+ position: absolute;
display: none;
background: white;
margin: 30px 0;
@@ -252,7 +252,7 @@ a:link:after, a:visited:after {
&:hover {
background: #eee;
}
- }
+ }
}
&.active {
@@ -329,6 +329,14 @@ a:link:after, a:visited:after {
border: 1px dotted #ccc;
}
}
+ .dpt-img {
+ img {
+ filter: grayscale(100%) contrast(110%);
+ opacity: 0.5;
+
+
+ }
+ }
}
a {
@@ -353,6 +361,12 @@ a:link:after, a:visited:after {
&.indent {
padding-left: 1em;
}
+ .dpt-img {
+ text-align: center;
+ img {
+ max-width: 100%;
+ }
+ }
.ementa {
padding: 2em 0em 2em 35%;
font-weight: bold;
@@ -417,8 +431,8 @@ a:link:after, a:visited:after {
margin-top: 0.3333em;
font-size: 1.15em;
}
-
- .texto_n_estruturado{
+
+ .texto_n_estruturado{
margin-top: 0.3333em;
font-size: 1.15em;
}
@@ -443,16 +457,16 @@ a:link:after, a:visited:after {
font-size: 1.0em;
margin-top: 2px;
}
-
+
.assinatura {
margin-top: 0.6em;
font-size: 1.15em;
}
-
+
.fecho_lei {
margin-top: 0.6em;
font-size: 1.15em;
- }
+ }
.page-break { page-break-before: always; }
.bloco_alteracao {
@@ -714,6 +728,7 @@ a:link:after, a:visited:after {
table, table td {
border: 1px dotted #ccc;
}
+
}
a.nota-alteracao {
@@ -1620,7 +1635,7 @@ a:link:after, a:visited:after {
}
}
-.cp-nav-parents {
+.cp-nav-parents {
.dropdown-menu {
left: 0;
right: auto;
@@ -1810,7 +1825,7 @@ a:link:after, a:visited:after {
height: 8px;
margin: -4px auto 0;
}
-
+
& > a {
font-size: 0.75rem;
}
@@ -1824,22 +1839,22 @@ a:link:after, a:visited:after {
margin-bottom: 4px;
}
}
-
+
ul {
a {
line-height: 1.3rem;
font-size: 0.7rem;
background: #fff;
- }
+ }
}
-
+
&.active {
.circle {
width: 14px;
height: 14px;
margin: -7px auto 0;
}
-
+
&:not(:last-child) {
& > a {
margin-bottom: 15px;
@@ -1857,13 +1872,13 @@ a:link:after, a:visited:after {
}
@media print {
- .cp .vigencias,
- .toggle-topbar,
- .menu-icon,
- .button,
- .tipo-vigencias,
+ .cp .vigencias,
+ .toggle-topbar,
+ .menu-icon,
+ .button,
+ .tipo-vigencias,
.dne,
- .cp-linha-vigencias,
+ .cp-linha-vigencias,
.tipo-vigencias {
display:none !important;
}
diff --git a/frontend/src/__global/js/image_cropping/image_cropping.js b/frontend/src/__global/js/image_cropping/image_cropping.js
index eb30eb1c2..5f787ae5c 100644
--- a/frontend/src/__global/js/image_cropping/image_cropping.js
+++ b/frontend/src/__global/js/image_cropping/image_cropping.js
@@ -1,4 +1,4 @@
-/* eslint-disable */
+/* eslint-disable */
var image_cropping = (function ($) {
var jcrop = {}
function init() {
@@ -184,7 +184,7 @@ var image_cropping = (function ($) {
}
})(jQuery)
-
+window.image_cropping = image_cropping
jQuery(function() {
/*var image_cropping_jquery_url = jQuery('.image-ratio:first').data('jquery-url')
if (image_cropping_jquery_url == "None") {
diff --git a/sapl/compilacao/forms.py b/sapl/compilacao/forms.py
index 0a7542a46..8f504425b 100644
--- a/sapl/compilacao/forms.py
+++ b/sapl/compilacao/forms.py
@@ -13,7 +13,10 @@ from django.forms.forms import Form
from django.forms.models import ModelForm
from django.template import defaultfilters
from django.utils.translation import ugettext_lazy as _
+from image_cropping.widgets import CropWidget, ImageCropWidget,\
+ get_attrs
from model_utils.choices import Choices
+from prompt_toolkit.key_binding.bindings.named_commands import self_insert
from sapl import utils
from sapl.compilacao.models import (NOTAS_PUBLICIDADE_CHOICES,
@@ -24,9 +27,20 @@ from sapl.compilacao.models import (NOTAS_PUBLICIDADE_CHOICES,
VeiculoPublicacao, Vide)
from sapl.compilacao.utils import DISPOSITIVO_SELECT_RELATED
from sapl.crispy_layout_mixin import SaplFormHelper
-from sapl.crispy_layout_mixin import SaplFormLayout, to_column, to_row,\
- form_actions
-from sapl.utils import YES_NO_CHOICES
+from sapl.crispy_layout_mixin import SaplFormLayout, to_column, to_row
+from sapl.utils import YES_NO_CHOICES, FileFieldCheckMixin
+
+
+class CustomImageCropWidget(ImageCropWidget):
+ """
+ Custom ImageCropWidget that doesn't show the initial value of the field.
+ We use this trick, and place it right under the CropWidget so that
+ it looks like the user is seeing the image and clearing the image.
+ """
+ template_with_initial = (
+ # '%(initial_text)s: %(initial)s '
+ '%(clear_template)s
%(input_text)s: %(input)s'
+ )
error_messages = {
@@ -513,11 +527,16 @@ class DispositivoIntegerField(forms.IntegerField):
min_value=0, *args, **kwargs)
-class DispositivoEdicaoBasicaForm(ModelForm):
+class DispositivoEdicaoBasicaForm(FileFieldCheckMixin, ModelForm):
class Meta:
model = Dispositivo
- fields = []
+ fields = ['imagem', 'imagem_cropping']
+
+ widgets = {
+ 'imagem': CustomImageCropWidget(),
+ 'imagem_cropping': CropWidget(),
+ }
error_messages = {
NON_FIELD_ERRORS: {
@@ -670,13 +689,24 @@ class DispositivoEdicaoBasicaForm(ModelForm):
DispositivoEdicaoBasicaForm.Meta.fields.remove(
'visibilidade')
- fields = DispositivoEdicaoBasicaForm.Meta.fields
- if fields:
- self.base_fields.clear()
- for f in fields:
+ if 'texto' in DispositivoEdicaoBasicaForm.Meta.fields and\
+ not editor_type:
+ layout.append(
+ Fieldset('Anexar Imagem',
+ to_row([('imagem', 7), ('imagem_cropping', 5), ]),
+ css_class="col-md-12"))
+ DispositivoEdicaoBasicaForm.Meta.fields.append('imagem')
+ DispositivoEdicaoBasicaForm.Meta.fields.append('imagem_cropping')
+
+ for f in DispositivoEdicaoBasicaForm.Meta.fields:
+ if hasattr(self, f):
self.base_fields.update({f: getattr(self, f)})
+ for f in set(self.base_fields.keys()) - set(DispositivoEdicaoBasicaForm.Meta.fields):
+ self.base_fields.pop(f)
+
self.helper = SaplFormHelper()
+ self.helper.include_media = False
if not editor_type:
cancel_label = _('Ir para o Editor Sequencial')
@@ -689,6 +719,14 @@ class DispositivoEdicaoBasicaForm(ModelForm):
super(DispositivoEdicaoBasicaForm, self).__init__(*args, **kwargs)
+ #imagem = self.fields['imagem'].widget
+ # imagem.attrs.update(
+ # get_attrs(self.instance.imagem, 'imagem')
+ #)
+
+ # if 'class' in imagem.attrs:
+ # imagem.attrs.pop('class')
+
def actions_get_form_base(self, layout,
inst,
texto_articulado_do_editor=None):
diff --git a/sapl/compilacao/migrations/0017_auto_20210225_1127.py b/sapl/compilacao/migrations/0017_auto_20210225_1127.py
new file mode 100644
index 000000000..df4ccca5a
--- /dev/null
+++ b/sapl/compilacao/migrations/0017_auto_20210225_1127.py
@@ -0,0 +1,25 @@
+# Generated by Django 2.2.13 on 2021-02-25 14:27
+
+from django.db import migrations
+import image_cropping.fields
+import sapl.compilacao.models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('compilacao', '0016_auto_20201013_1159'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='dispositivo',
+ name='imagem',
+ field=image_cropping.fields.ImageCropField(blank=True, null=True, upload_to=sapl.compilacao.models.imagem_upload_path, verbose_name='Imagem'),
+ ),
+ migrations.AddField(
+ model_name='dispositivo',
+ name='imagem_cropping',
+ field=image_cropping.fields.ImageRatioField('imagem', '0x0', adapt_rotation=False, allow_fullsize=False, free_crop=False, help_text='O recorte de imagem é possível após a atualização.', hide_image_field=False, size_warning=True, verbose_name='Recorte de Imagem'),
+ ),
+ ]
diff --git a/sapl/compilacao/models.py b/sapl/compilacao/models.py
index bde388b23..3c6fee330 100644
--- a/sapl/compilacao/models.py
+++ b/sapl/compilacao/models.py
@@ -1,5 +1,3 @@
-
-from bs4 import BeautifulSoup
from django.contrib import messages
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
@@ -13,11 +11,13 @@ from django.utils import timezone
from django.utils.decorators import classonlymethod
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
+from image_cropping.fields import ImageCropField, ImageRatioField
import reversion
from sapl.compilacao.utils import (get_integrations_view_names, int_to_letter,
int_to_roman)
-from sapl.utils import YES_NO_CHOICES, get_settings_auth_user_model
+from sapl.utils import YES_NO_CHOICES, get_settings_auth_user_model,\
+ texto_upload_path, restringe_tipos_de_arquivo_img
@reversion.register()
@@ -965,6 +965,10 @@ class Publicacao(TimestampedMixin):
self.ta)
+def imagem_upload_path(instance, filename):
+ return texto_upload_path(instance, filename, subpath='')
+
+
@reversion.register()
class Dispositivo(BaseModel, TimestampedMixin):
TEXTO_PADRAO_DISPOSITIVO_REVOGADO = force_text(_('(Revogado)'))
@@ -1186,6 +1190,17 @@ class Dispositivo(BaseModel, TimestampedMixin):
verbose_name=_('Contagem contínua')
)
+ imagem = ImageCropField(
+ verbose_name=_('Imagem'),
+ upload_to=imagem_upload_path,
+ validators=[restringe_tipos_de_arquivo_img], null=True, blank=True)
+
+ imagem_cropping = ImageRatioField(
+ 'imagem', '100x100', verbose_name=_('Recorte de Imagem'),
+ free_crop=True, size_warning=True,
+ help_text=_('O recorte de imagem '
+ 'é possível após a atualização.'))
+
class Meta:
verbose_name = _('Dispositivo')
verbose_name_plural = _('Dispositivos')
diff --git a/sapl/parlamentares/models.py b/sapl/parlamentares/models.py
index c02c4677a..f9ced6221 100644
--- a/sapl/parlamentares/models.py
+++ b/sapl/parlamentares/models.py
@@ -271,6 +271,7 @@ class Parlamentar(models.Model):
verbose_name=_('Ativo na Casa?'))
biografia = models.TextField(
blank=True, verbose_name=_('Biografia'))
+
fotografia = ImageCropField(
verbose_name=_('Fotografia'), upload_to=foto_upload_path,
validators=[restringe_tipos_de_arquivo_img], null=True, blank=True)
diff --git a/sapl/templates/compilacao/text_edit_bloco.html b/sapl/templates/compilacao/text_edit_bloco.html
index a90c2ecd7..496122bbc 100644
--- a/sapl/templates/compilacao/text_edit_bloco.html
+++ b/sapl/templates/compilacao/text_edit_bloco.html
@@ -1,5 +1,5 @@
{% load i18n %}
-{% load compilacao_filters %}
+{% load compilacao_filters cropping%}
{% load common_tags %}
{% dispositivotree dispositivos_list %}
@@ -53,11 +53,18 @@
{% endif %}
+
+ {% if node.dpt.imagem %}
+