summaryrefslogtreecommitdiff
path: root/ishtar_common/widgets.py
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2021-03-19 11:05:22 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2021-03-19 11:05:22 +0100
commite2d6c50f231f636fed362be37e7bf3319fc5d6b8 (patch)
tree5d7fde3628825aebeeef3d85d2dfcf09a52116de /ishtar_common/widgets.py
parente6af0225df8f539308bc3fd8c9dbc967bba5a807 (diff)
downloadIshtar-e2d6c50f231f636fed362be37e7bf3319fc5d6b8.tar.bz2
Ishtar-e2d6c50f231f636fed362be37e7bf3319fc5d6b8.zip
Format - black: ishtar_common
Diffstat (limited to 'ishtar_common/widgets.py')
-rw-r--r--ishtar_common/widgets.py696
1 files changed, 390 insertions, 306 deletions
diff --git a/ishtar_common/widgets.py b/ishtar_common/widgets.py
index 67a16e4b7..8f95f4521 100644
--- a/ishtar_common/widgets.py
+++ b/ishtar_common/widgets.py
@@ -29,8 +29,10 @@ from django.core.urlresolvers import reverse, NoReverseMatch
from django.db.models import fields
from django.forms import ClearableFileInput
from django.forms.utils import flatatt
-from django.forms.widgets import CheckboxSelectMultiple as \
- CheckboxSelectMultipleBase, NumberInput
+from django.forms.widgets import (
+ CheckboxSelectMultiple as CheckboxSelectMultipleBase,
+ NumberInput,
+)
from django.template import loader
from django.template.defaultfilters import slugify
from django.utils.encoding import smart_text
@@ -48,8 +50,8 @@ reverse_lazy = lazy(reverse, str)
class SelectReadonly(forms.Select):
- template_name = 'blocks/readonly_input.html'
- option_template_name = 'blocks/readonly_input_option.html'
+ template_name = "blocks/readonly_input.html"
+ option_template_name = "blocks/readonly_input_option.html"
def __init__(self, attrs=None, choices=(), model=None, available=None):
super(SelectReadonly, self).__init__(attrs, choices)
@@ -63,7 +65,7 @@ class SelectReadonly(forms.Select):
if value:
q = q.filter(pk=value)
for i in q.all():
- if hasattr(self.model, 'verbose_name'):
+ if hasattr(self.model, "verbose_name"):
label = i.verbose_name
else:
label = str(i)
@@ -77,18 +79,27 @@ class SelectReadonly(forms.Select):
class SelectReadonlyField(forms.ChoiceField):
- def __init__(self, choices=(), required=True, widget=None, label=None,
- initial=None, help_text='', *args, **kwargs):
+ def __init__(
+ self,
+ choices=(),
+ required=True,
+ widget=None,
+ label=None,
+ initial=None,
+ help_text="",
+ *args,
+ **kwargs
+ ):
self.available = False
self.model = None
- if 'model' in kwargs:
- self.model = kwargs.pop('model')
- if 'available' in kwargs:
- self.available = kwargs.pop('available')
+ if "model" in kwargs:
+ self.model = kwargs.pop("model")
+ if "available" in kwargs:
+ self.available = kwargs.pop("available")
widget = SelectReadonly(model=self.model, available=self.available)
super(SelectReadonlyField, self).__init__(
- choices, required, widget, label, initial, help_text, *args,
- **kwargs)
+ choices, required, widget, label, initial, help_text, *args, **kwargs
+ )
def get_q(self):
q = self.model.objects
@@ -106,12 +117,10 @@ class Select2Media(object):
@property
def media(self):
media = super(Select2Media, self).media
- css = {
- 'all': ('select2/css/select2.css',)
- }
- js = ['select2/js/select2.full.min.js']
+ css = {"all": ("select2/css/select2.css",)}
+ js = ["select2/js/select2.full.min.js"]
for lang_code, lang in settings.LANGUAGES:
- js.append('select2/js/i18n/{}.js'.format(lang_code))
+ js.append("select2/js/i18n/{}.js".format(lang_code))
media.add_css(css)
media.add_js(js)
return media
@@ -123,20 +132,20 @@ class Select2Dynamic(Select2Media, forms.Select):
"""
def render(self, name, value, attrs=None, choices=()):
- choices = choices or getattr(self, 'choices', [])
+ choices = choices or getattr(self, "choices", [])
if value and value not in [key for key, v in choices]:
choices.insert(1, (value, value))
self.choices = choices
- klass = attrs and attrs.get('class') or ''
- klass += ' ' if klass else '' + 'js-select2'
+ klass = attrs and attrs.get("class") or ""
+ klass += " " if klass else "" + "js-select2"
if not attrs:
attrs = {}
- attrs['class'] = klass
- if 'style' not in attrs:
- if attrs.get('full-width', None):
- attrs['style'] = "width: calc(100% - 60px)"
+ attrs["class"] = klass
+ if "style" not in attrs:
+ if attrs.get("full-width", None):
+ attrs["style"] = "width: calc(100% - 60px)"
else:
- attrs['style'] = "width: 370px"
+ attrs["style"] = "width: 370px"
options = [
"tags: true",
]
@@ -149,7 +158,7 @@ class Select2Dynamic(Select2Media, forms.Select):
return confirm("{}");
}}""".format(msg))
'''
- if attrs.get('full-width', None):
+ if attrs.get("full-width", None):
options.append("containerCssClass: 'full-width'")
html = super(Select2Dynamic, self).render(name, value, attrs)
@@ -157,7 +166,9 @@ class Select2Dynamic(Select2Media, forms.Select):
$(document).ready(function() {{
$("#id_{}").select2({{ {} }});
}});</script>
- """.format(name, ", ".join(options))
+ """.format(
+ name, ", ".join(options)
+ )
return mark_safe(html)
@@ -170,9 +181,7 @@ class Select2DynamicField(forms.ChoiceField):
used.
"""
if value and '"' in value:
- raise ValidationError(
- _("The character \" is not accepted.")
- )
+ raise ValidationError(_('The character " is not accepted.'))
def to_python(self, value):
"""
@@ -182,8 +191,9 @@ class Select2DynamicField(forms.ChoiceField):
class Select2Base(Select2Media):
- def __init__(self, attrs=None, choices=(), remote=None, model=None,
- new=None, available=None):
+ def __init__(
+ self, attrs=None, choices=(), remote=None, model=None, new=None, available=None
+ ):
self.remote = remote
self.available = available
self.model = model
@@ -202,35 +212,36 @@ class Select2Base(Select2Media):
def render(self, name, value, attrs=None, choices=()):
self.remote = str(self.remote)
- if self.remote in ('None', 'false'):
+ if self.remote in ("None", "false"):
# test on lazy object is buggy... so we have this ugly test
self.remote = None
if not choices:
if not self.remote and self.model:
choices = self.get_choices()
- if hasattr(self, 'choices') and self.choices:
+ if hasattr(self, "choices") and self.choices:
choices = self.choices
new_attrs = self.attrs.copy()
new_attrs.update(attrs)
attrs = new_attrs
- klass = attrs and attrs.get('class') or ''
- klass += ' ' if klass else '' + 'js-select2'
+ klass = attrs and attrs.get("class") or ""
+ klass += " " if klass else "" + "js-select2"
if not attrs:
attrs = {}
- attrs['class'] = klass
- if 'style' not in attrs:
- if attrs.get('full-width', None):
- attrs['style'] = "width: calc(100% - 60px)"
+ attrs["class"] = klass
+ if "style" not in attrs:
+ if attrs.get("full-width", None):
+ attrs["style"] = "width: calc(100% - 60px)"
else:
- attrs['style'] = "width: 370px"
+ attrs["style"] = "width: 370px"
if value:
if type(value) not in (list, tuple):
- value = value.split(',')
+ value = value.split(",")
options = ""
if self.remote:
- options = """{
+ options = (
+ """{
ajax: {
url: '%s',
delay: 250,
@@ -249,7 +260,9 @@ class Select2Base(Select2Media):
}
}
}
- }""" % self.remote
+ }"""
+ % self.remote
+ )
if value:
choices = []
for v in value:
@@ -258,7 +271,7 @@ class Select2Base(Select2Media):
except (self.model.DoesNotExist, ValueError):
# an old reference? it should not happen
pass
- if attrs.get('full-width', None):
+ if attrs.get("full-width", None):
if options:
options = options[:-1] + ", "
else:
@@ -269,14 +282,16 @@ class Select2Base(Select2Media):
new, html = "", ""
if self.new:
html = "<div class='input-group'>"
- url_new = 'new-' + self.model.SLUG
+ url_new = "new-" + self.model.SLUG
url_new = reverse(url_new, args=["id_" + name])
# WARNING: the modal for the form must be in the main template
# "extra_form_modals" list is used for that in form or view
- new = """<span class="input-group-append">"""\
- """<a href="#" class="add-button input-group-text" """\
- """onclick="dt_qa_open('{}', 'modal-dynamic-form-{}');">"""\
- """+</a></span></div>""".format(url_new, self.model.SLUG)
+ new = (
+ """<span class="input-group-append">"""
+ """<a href="#" class="add-button input-group-text" """
+ """onclick="dt_qa_open('{}', 'modal-dynamic-form-{}');">"""
+ """+</a></span></div>""".format(url_new, self.model.SLUG)
+ )
html += super(Select2Base, self).render(name, value, attrs)
html += new
@@ -284,7 +299,9 @@ class Select2Base(Select2Media):
$(document).ready(function() {{
$("#id_{}").select2({});
}});</script>
- """.format(name, options)
+ """.format(
+ name, options
+ )
return mark_safe(html)
@@ -302,9 +319,10 @@ class CheckboxSelectMultiple(CheckboxSelectMultipleBase):
Should be corrected on recent Django version.
TODO: test and remove (test case: treatment type not keep on modif)
"""
+
def render(self, name, value, attrs=None, choices=()):
if type(value) in (str, str):
- value = value.split(',')
+ value = value.split(",")
if not isinstance(value, (list, tuple)):
value = [value]
return super(CheckboxSelectMultiple, self).render(name, value, attrs)
@@ -315,36 +333,40 @@ class Select2BaseField(object):
def __init__(self, *args, **kwargs):
new = None
- if 'new' in kwargs:
- new = kwargs.pop('new')
+ if "new" in kwargs:
+ new = kwargs.pop("new")
remote = None
- if 'remote' in kwargs:
- remote = kwargs.pop('remote')
+ if "remote" in kwargs:
+ remote = kwargs.pop("remote")
self.model, self.remote = None, None
- if 'model' in kwargs:
- self.model = kwargs.pop('model')
+ if "model" in kwargs:
+ self.model = kwargs.pop("model")
if remote:
self.remote = reverse_lazy(
- 'autocomplete-' + self.model.__name__.lower())
+ "autocomplete-" + self.model.__name__.lower()
+ )
long_widget = False
- if 'long_widget' in kwargs:
- long_widget = kwargs.pop('long_widget')
+ if "long_widget" in kwargs:
+ long_widget = kwargs.pop("long_widget")
self.available = False
- if 'available' in kwargs:
- self.available = kwargs.pop('available')
+ if "available" in kwargs:
+ self.available = kwargs.pop("available")
attrs = {}
if long_widget:
- attrs['cols'] = True
- attrs['full-width'] = True
+ attrs["cols"] = True
+ attrs["full-width"] = True
if self.multiple:
widget = Select2Multiple
else:
widget = Select2Simple
if kwargs.get("style", None):
attrs["style"] = kwargs.pop("style")
- kwargs['widget'] = widget(
- model=self.model, available=self.available, remote=self.remote,
- new=new, attrs=attrs
+ kwargs["widget"] = widget(
+ model=self.model,
+ available=self.available,
+ remote=self.remote,
+ new=new,
+ attrs=attrs,
)
super(Select2BaseField, self).__init__(*args, **kwargs)
@@ -366,7 +388,7 @@ class Select2MultipleField(Select2BaseField, forms.MultipleChoiceField):
def to_python(self, value):
if not isinstance(value, (list, tuple)):
if value:
- value = value.split(',')
+ value = value.split(",")
else:
value = []
return super(Select2MultipleField, self).to_python(value)
@@ -380,8 +402,8 @@ class DeleteWidget(forms.CheckboxInput):
def render(self, name, value, attrs=None, renderer=None):
final_attrs = flatatt(
self.build_attrs(
- attrs, {"name": name, "value": '1',
- 'class': "btn btn-danger"})
+ attrs, {"name": name, "value": "1", "class": "btn btn-danger"}
+ )
)
output = "<button%s>%s</button>" % (final_attrs, _("Delete"))
@@ -394,22 +416,26 @@ class SwitchWidget(forms.CheckboxInput):
def render(self, name, value, attrs=None, renderer=None):
extra_class = (" " + self.extra_class) if self.extra_class else ""
- default = {"name": name, "value": "1",
- 'class': "switch" + extra_class,
- 'type': 'checkbox'}
+ default = {
+ "name": name,
+ "value": "1",
+ "class": "switch" + extra_class,
+ "type": "checkbox",
+ }
if value:
- default['checked'] = 'checked'
- attrs = self.build_attrs(
- attrs, default
- )
+ default["checked"] = "checked"
+ attrs = self.build_attrs(attrs, default)
final_attrs = flatatt(attrs)
extra_label = ""
if self.extra_label:
- extra_label = '<label for="{}">{}</label>'.format(attrs['id'],
- self.extra_label)
+ extra_label = '<label for="{}">{}</label>'.format(
+ attrs["id"], self.extra_label
+ )
output = """<span class="switch{}">
<input{}>{}
-</span>""".format(extra_class, final_attrs, extra_label)
+</span>""".format(
+ extra_class, final_attrs, extra_label
+ )
return mark_safe(output)
@@ -419,7 +445,7 @@ class DeleteSwitchWidget(SwitchWidget):
class ImageFileInput(ClearableFileInput):
- template_name = 'widgets/image_input.html'
+ template_name = "widgets/image_input.html"
NO_FORM_CONTROL = True
def format_value(self, value):
@@ -427,15 +453,16 @@ class ImageFileInput(ClearableFileInput):
return value
# try to display posted images
try:
- has_file = hasattr(value, 'file')
+ has_file = hasattr(value, "file")
except ValueError:
has_file = False
if has_file:
- if hasattr(value, 'file'):
+ if hasattr(value, "file"):
full_path = str(value.file)
if full_path.startswith(settings.MEDIA_ROOT):
- value.url = settings.MEDIA_URL + full_path[
- len(settings.MEDIA_ROOT):]
+ value.url = (
+ settings.MEDIA_URL + full_path[len(settings.MEDIA_ROOT) :]
+ )
elif value:
full_path = settings.MEDIA_ROOT + str(value)
try:
@@ -450,16 +477,15 @@ class ImageFileInput(ClearableFileInput):
def get_context(self, name, value, attrs):
context = super(ImageFileInput, self).get_context(name, value, attrs)
- if getattr(self, 'hidden', None):
- context['hidden_value'] = self.hidden
+ if getattr(self, "hidden", None):
+ context["hidden_value"] = self.hidden
# on post memory file is used: display the name
- if getattr(self, 'hidden_name', None):
- context['hidden_name_value'] = self.hidden_name
+ if getattr(self, "hidden_name", None):
+ context["hidden_name_value"] = self.hidden_name
return context
def value_from_datadict(self, data, files, name):
- value = super(ImageFileInput, self).value_from_datadict(
- data, files, name)
+ value = super(ImageFileInput, self).value_from_datadict(data, files, name)
hidden_name = name + "-hidden"
hidden_name_value = name + "-hidden-name"
self.hidden, self.hidden_name = None, None
@@ -482,11 +508,12 @@ class CustomWidget(forms.TextInput):
def render(self, name, value, attrs=None, renderer=None):
if not value:
value = ""
- final_attrs = flatatt(
- self.build_attrs(attrs, {"name": name, "value": value}))
- dct = {'final_attrs': final_attrs,
- 'id': attrs['id'],
- "safe_id": attrs['id'].replace('-', '_')}
+ final_attrs = flatatt(self.build_attrs(attrs, {"name": name, "value": value}))
+ dct = {
+ "final_attrs": final_attrs,
+ "id": attrs["id"],
+ "safe_id": attrs["id"].replace("-", "_"),
+ }
dct.update(self.EXTRA_DCT)
t = loader.get_template(self.TEMPLATE)
rendered = t.render(dct)
@@ -494,33 +521,33 @@ class CustomWidget(forms.TextInput):
class SquareMeterWidget(CustomWidget):
- TEMPLATE = 'widgets/SquareMeterWidget.html'
- EXTRA_DCT = {'unit': settings.SURFACE_UNIT_LABEL}
+ TEMPLATE = "widgets/SquareMeterWidget.html"
+ EXTRA_DCT = {"unit": settings.SURFACE_UNIT_LABEL}
class GramKilogramWidget(CustomWidget):
- TEMPLATE = 'widgets/GramKilogramWidget.html'
- EXTRA_DCT = {'unit': "g"}
+ TEMPLATE = "widgets/GramKilogramWidget.html"
+ EXTRA_DCT = {"unit": "g"}
class CentimeterMeterWidget(CustomWidget):
- TEMPLATE = 'widgets/CentimeterMeterWidget.html'
- EXTRA_DCT = {'unit': "cm"}
+ TEMPLATE = "widgets/CentimeterMeterWidget.html"
+ EXTRA_DCT = {"unit": "cm"}
AreaWidget = forms.TextInput
-if settings.SURFACE_UNIT == 'square-metre':
+if settings.SURFACE_UNIT == "square-metre":
AreaWidget = SquareMeterWidget
class ISBNWidget(CustomWidget):
- TEMPLATE = 'widgets/CheckTextWidget.html'
- EXTRA_DCT = {'validator': "is_valid_isbn"}
+ TEMPLATE = "widgets/CheckTextWidget.html"
+ EXTRA_DCT = {"validator": "is_valid_isbn"}
class ISSNWidget(CustomWidget):
- TEMPLATE = 'widgets/CheckTextWidget.html'
- EXTRA_DCT = {'validator': "is_valid_issn"}
+ TEMPLATE = "widgets/CheckTextWidget.html"
+ EXTRA_DCT = {"validator": "is_valid_issn"}
class CheckboxInput(forms.CheckboxInput):
@@ -528,7 +555,7 @@ class CheckboxInput(forms.CheckboxInput):
class SearchWidget(forms.TextInput):
- template_name = 'widgets/search_input.html'
+ template_name = "widgets/search_input.html"
def __init__(self, app_name=None, model=None, pin_model=None, attrs=None):
super(SearchWidget, self).__init__(attrs)
@@ -540,9 +567,9 @@ class SearchWidget(forms.TextInput):
def get_context(self, name, value, attrs):
context = super(SearchWidget, self).get_context(name, value, attrs)
- context['app_name'] = self.app_name
- context['model'] = self.model
- context['pin_model'] = self.pin_model
+ context["app_name"] = self.app_name
+ context["model"] = self.model
+ context["pin_model"] = self.pin_model
return context
@@ -560,9 +587,7 @@ class ModelFieldMixin(object):
values.append(self.model.objects.get(pk=v))
except self.model.DoesNotExist:
raise ValidationError(
- str(
- _("{} is not a valid key for {}")
- ).format(v, self.model)
+ str(_("{} is not a valid key for {}")).format(v, self.model)
)
if not self.multiple:
return values[0]
@@ -576,32 +601,47 @@ class ModelChoiceField(ModelFieldMixin, forms.ChoiceField):
super(ModelFieldMixin, self).__init__(*args, **kwargs)
def valid_value(self, value):
- if value and getattr(value, 'pk', None) in [v for v, l in self.choices]:
+ if value and getattr(value, "pk", None) in [v for v, l in self.choices]:
return True
return super(ModelChoiceField, self).valid_value(value)
class ModelJQueryAutocompleteField(ModelFieldMixin, forms.CharField):
- def __init__(self, model, multiple=False, new=False, long_widget=False,
- *args, **kwargs):
+ def __init__(
+ self, model, multiple=False, new=False, long_widget=False, *args, **kwargs
+ ):
self.model = model
self.multiple = multiple
attrs = {}
if long_widget:
- attrs['cols'] = True
- attrs['full-width'] = True
- kwargs['widget'] = JQueryAutoComplete(
- reverse_lazy('autocomplete-' + self.model.SLUG),
- associated_model=self.model, new=new, multiple=multiple,
- attrs=attrs
+ attrs["cols"] = True
+ attrs["full-width"] = True
+ kwargs["widget"] = JQueryAutoComplete(
+ reverse_lazy("autocomplete-" + self.model.SLUG),
+ associated_model=self.model,
+ new=new,
+ multiple=multiple,
+ attrs=attrs,
)
super(ModelJQueryAutocompleteField, self).__init__(*args, **kwargs)
class JQueryAutoComplete(forms.TextInput):
- def __init__(self, source, associated_model=None, options=None, attrs=None,
- new=False, url_new='', multiple=False, limit=None,
- dynamic_limit=None, detail=False, modify=False, tips=""):
+ def __init__(
+ self,
+ source,
+ associated_model=None,
+ options=None,
+ attrs=None,
+ new=False,
+ url_new="",
+ multiple=False,
+ limit=None,
+ dynamic_limit=None,
+ detail=False,
+ modify=False,
+ tips="",
+ ):
"""
Source can be a list containing the autocomplete values or a
string containing the url used for the request.
@@ -631,7 +671,7 @@ class JQueryAutoComplete(forms.TextInput):
if not self.multiple:
return data.get(name, None)
if type(v) == str and "," in v:
- return [item.strip() for item in v.split(',') if item.strip()]
+ return [item.strip() for item in v.split(",") if item.strip()]
return data.getlist(name, None)
def render_js(self, field_id, current_pk):
@@ -643,36 +683,42 @@ class JQueryAutoComplete(forms.TextInput):
try:
source = "'" + str(self.source) + "'"
except:
- raise ValueError('{} source type is not valid'.format(
- self.source))
+ raise ValueError("{} source type is not valid".format(self.source))
dynamic_limit = []
for lim in self.dynamic_limit:
- field_ids = field_id.split('-')
+ field_ids = field_id.split("-")
if field_ids[1:-1]:
dynamic_limit.append(
- 'id_' + lim.replace('_', '') + '-' +
- '-'.join(field_ids[1:-1]) + '-' + lim)
+ "id_"
+ + lim.replace("_", "")
+ + "-"
+ + "-".join(field_ids[1:-1])
+ + "-"
+ + lim
+ )
else:
- dynamic_limit.append('id_' + lim.replace('_', ''))
-
- dct = {'source': mark_safe(source),
- 'field_id': field_id,
- 'safe_field_id': field_id.replace("-", "_"),
- "modify": self.modify,
- 'dynamic_limit': dynamic_limit}
+ dynamic_limit.append("id_" + lim.replace("_", ""))
+
+ dct = {
+ "source": mark_safe(source),
+ "field_id": field_id,
+ "safe_field_id": field_id.replace("-", "_"),
+ "modify": self.modify,
+ "dynamic_limit": dynamic_limit,
+ }
if self.associated_model:
model_name = self.associated_model._meta.object_name.lower()
dct["model_name"] = model_name
if self.detail:
model_name = self.associated_model._meta.object_name.lower()
- url_detail = '/detail-{}/'.format(model_name)
+ url_detail = "/detail-{}/".format(model_name)
dct["detail"] = url_detail
if self.options:
- dct['options'] = mark_safe('%s' % self.options)
+ dct["options"] = mark_safe("%s" % self.options)
- tpl = 'blocks/JQueryAutocomplete.js'
+ tpl = "blocks/JQueryAutocomplete.js"
if self.multiple:
- tpl = 'blocks/JQueryAutocompleteMultiple.js'
+ tpl = "blocks/JQueryAutocompleteMultiple.js"
t = loader.get_template(tpl)
js = t.render(dct)
return js
@@ -680,19 +726,19 @@ class JQueryAutoComplete(forms.TextInput):
def render(self, name, value, attrs=None, renderer=None):
attrs_hidden = self.build_attrs(attrs, {"name": name})
attrs_select = self.build_attrs(attrs)
- attrs_select['placeholder'] = _("Search...")
+ attrs_select["placeholder"] = _("Search...")
values = []
if value:
hiddens = []
selects = []
if type(value) not in (list, tuple):
values = str(escape(smart_text(value)))
- values = values.replace('[', '').replace(']', '')
- values = values.split(',')
+ values = values.replace("[", "").replace("]", "")
+ values = values.split(",")
else:
values = []
for v in value:
- values += v.split(',')
+ values += v.split(",")
for v in values:
if not v:
continue
@@ -700,28 +746,27 @@ class JQueryAutoComplete(forms.TextInput):
selects.append(v)
if self.associated_model:
try:
- selects[-1] = str(
- self.associated_model.objects.get(pk=v))
+ selects[-1] = str(self.associated_model.objects.get(pk=v))
except (self.associated_model.DoesNotExist, ValueError):
selects.pop()
hiddens.pop()
if self.multiple:
- attrs_hidden['value'] = ", ".join(hiddens)
+ attrs_hidden["value"] = ", ".join(hiddens)
if selects:
selects.append("")
- attrs_select['value'] = ", ".join(selects)
+ attrs_select["value"] = ", ".join(selects)
else:
if hiddens and selects:
- attrs_hidden['value'] = hiddens[0]
- attrs_select['value'] = selects[0]
- if 'id' not in self.attrs:
- attrs_hidden['id'] = 'id_%s' % name
- attrs_select['id'] = 'id_select_%s' % name
- if 'class' not in attrs_select:
- attrs_select['class'] = 'autocomplete'
-
- has_previous_value = 'value' in attrs_select and attrs_select['value']
- attrs_select['class'] += ' form-control'
+ attrs_hidden["value"] = hiddens[0]
+ attrs_select["value"] = selects[0]
+ if "id" not in self.attrs:
+ attrs_hidden["id"] = "id_%s" % name
+ attrs_select["id"] = "id_select_%s" % name
+ if "class" not in attrs_select:
+ attrs_select["class"] = "autocomplete"
+
+ has_previous_value = "value" in attrs_select and attrs_select["value"]
+ attrs_select["class"] += " form-control"
new = ""
html = ""
if self.tips or self.new or self.modify:
@@ -740,7 +785,9 @@ class JQueryAutoComplete(forms.TextInput):
<span class="add-button input-group-text">
<em id="{}-tips">{}</em>
</span></span>
- """.format(attrs_hidden['id'], tips)
+ """.format(
+ attrs_hidden["id"], tips
+ )
if self.modify:
new += """
<span class="input-group-append">
@@ -748,17 +795,16 @@ class JQueryAutoComplete(forms.TextInput):
onclick="{}_modify();">
<i class="fa fa-pencil"></i></a>
</span>""".format(
- attrs_hidden['id'],
- name.replace("-", "_"))
+ attrs_hidden["id"], name.replace("-", "_")
+ )
if self.new:
limits = []
for k in self.limit:
- limits.append(k + "__" + "-".join(
- [str(v) for v in self.limit[k]]))
- args = [attrs_select['id']]
+ limits.append(k + "__" + "-".join([str(v) for v in self.limit[k]]))
+ args = [attrs_select["id"]]
if limits:
- args.append(';'.join(limits))
- url_new = 'new-' + model_name
+ args.append(";".join(limits))
+ url_new = "new-" + model_name
if self.url_new:
url_new = self.url_new
url_new = reverse(url_new, args=args)
@@ -767,12 +813,16 @@ class JQueryAutoComplete(forms.TextInput):
<a href="#" class="add-button input-group-text"
onclick="dt_qa_open('{}', 'modal-dynamic-form-{}');">+</a>
</span>
- """.format(url_new, model_name, model_name)
+ """.format(
+ url_new, model_name, model_name
+ )
new += "</div>"
detail = ""
if self.detail:
detail = """<div class="form-control detail-value" id="{}-detail">
- </div>""".format(attrs_hidden['id'])
+ </div>""".format(
+ attrs_hidden["id"]
+ )
old_value = ""
if has_previous_value:
@@ -790,16 +840,17 @@ class JQueryAutoComplete(forms.TextInput):
</span>
</div>""".format(
_("Prev.:"),
- attrs_hidden['id'] + "_previous_label",
- attrs_select['value'],
- attrs_hidden['id'] + "_previous_button",
- _("Restore previous")
+ attrs_hidden["id"] + "_previous_label",
+ attrs_select["value"],
+ attrs_hidden["id"] + "_previous_button",
+ _("Restore previous"),
)
attrs_hidden_previous = attrs_hidden.copy()
- attrs_hidden_previous['name'] += "_previous"
- attrs_hidden_previous['id'] += "_previous"
+ attrs_hidden_previous["name"] += "_previous"
+ attrs_hidden_previous["id"] += "_previous"
old_value += "<input type='hidden'{}>".format(
- flatatt(attrs_hidden_previous))
+ flatatt(attrs_hidden_previous)
+ )
pk = None
if values:
pk = values[0]
@@ -813,8 +864,9 @@ class JQueryAutoComplete(forms.TextInput):
old_value=old_value,
attrs_select=flatatt(attrs_select),
attrs_hidden=flatatt(attrs_hidden),
- js=self.render_js(name, pk), new=new,
- detail=detail
+ js=self.render_js(name, pk),
+ new=new,
+ detail=detail,
)
return html
@@ -824,8 +876,7 @@ class JQueryTown(forms.TextInput):
Town fields with state and department pre-selections
"""
- def __init__(self, source, options={},
- attrs={}, new=False, limit={}):
+ def __init__(self, source, options={}, attrs={}, new=False, limit={}):
self.options = None
self.attrs = {}
self.source = source
@@ -841,37 +892,37 @@ class JQueryTown(forms.TextInput):
encoded_src = JSONEncoder().encode(source)
elif isinstance(source, str):
src = escape(source)
- if not src.endswith('/'):
+ if not src.endswith("/"):
src += "/"
encoded_src = "'%s'" % src
else:
try:
src = str(source)
- if not src.endswith('/'):
+ if not src.endswith("/"):
src += "/"
encoded_src = "'%s'" % src
except:
- raise ValueError('source type is not valid')
+ raise ValueError("source type is not valid")
return encoded_src
def render(self, name, value, attrs=None, renderer=None):
attrs_hidden = self.build_attrs(attrs, {"name": name})
attrs_select = self.build_attrs(attrs)
- attrs_select['placeholder'] = _("Search...")
- selected = ''
- selected_state = ''
- selected_department = ''
+ attrs_select["placeholder"] = _("Search...")
+ selected = ""
+ selected_state = ""
+ selected_department = ""
if value:
hiddens = []
selects = []
if type(value) not in (list, tuple):
values = str(escape(smart_text(value)))
- values = values.replace('[', '').replace(']', '')
- values = values.split(',')
+ values = values.replace("[", "").replace("]", "")
+ values = values.split(",")
else:
values = []
for v in value:
- values += v.split(',')
+ values += v.split(",")
for v in values:
if not v:
continue
@@ -889,31 +940,35 @@ class JQueryTown(forms.TextInput):
selects.pop()
hiddens.pop()
if hiddens and selects:
- attrs_hidden['value'] = hiddens[0]
- attrs_select['value'] = selects[0]
- if 'id' not in self.attrs:
- attrs_hidden['id'] = 'id_%s' % name
- attrs_select['id'] = 'id_select_%s' % name
- if 'class' not in attrs_select:
- attrs_select['class'] = 'autocomplete'
+ attrs_hidden["value"] = hiddens[0]
+ attrs_select["value"] = selects[0]
+ if "id" not in self.attrs:
+ attrs_hidden["id"] = "id_%s" % name
+ attrs_select["id"] = "id_select_%s" % name
+ if "class" not in attrs_select:
+ attrs_select["class"] = "autocomplete"
source = self.encode_source(self.source)
- dct = {'source': mark_safe(source),
- 'selected': selected,
- 'safe_field_id': slugify(name).replace('-', '_'),
- 'field_id': name}
+ dct = {
+ "source": mark_safe(source),
+ "selected": selected,
+ "safe_field_id": slugify(name).replace("-", "_"),
+ "field_id": name,
+ }
if self.options:
- dct['options'] = mark_safe('%s' % self.options)
-
- dct.update({'attrs_select': mark_safe(flatatt(attrs_select)),
- 'attrs_hidden': mark_safe(flatatt(attrs_hidden)),
- 'name': name,
- 'states': models.State.objects.all().order_by('label'),
- 'selected_department': selected_department,
- 'selected_state': selected_state}
- )
- html = loader.get_template('blocks/JQueryAdvancedTown.html')\
- .render(dct)
+ dct["options"] = mark_safe("%s" % self.options)
+
+ dct.update(
+ {
+ "attrs_select": mark_safe(flatatt(attrs_select)),
+ "attrs_hidden": mark_safe(flatatt(attrs_hidden)),
+ "name": name,
+ "states": models.State.objects.all().order_by("label"),
+ "selected_department": selected_department,
+ "selected_state": selected_state,
+ }
+ )
+ html = loader.get_template("blocks/JQueryAdvancedTown.html").render(dct)
return html
@@ -925,10 +980,18 @@ class JQueryPersonOrganization(forms.TextInput):
* create new person and new organization
"""
- def __init__(self, source, edit_source, model, options={},
- attrs={}, new=False, limit={},
- html_template='blocks/PersonOrganization.html',
- js_template='blocks/JQueryPersonOrganization.js'):
+ def __init__(
+ self,
+ source,
+ edit_source,
+ model,
+ options={},
+ attrs={},
+ new=False,
+ limit={},
+ html_template="blocks/PersonOrganization.html",
+ js_template="blocks/JQueryPersonOrganization.js",
+ ):
self.options = None
self.attrs = {}
self.model = model
@@ -946,45 +1009,46 @@ class JQueryPersonOrganization(forms.TextInput):
def encode_source(cls, source):
if isinstance(source, list):
encoded_src = JSONEncoder().encode(source)
- elif isinstance(source, str) \
- or isinstance(source, str):
+ elif isinstance(source, str) or isinstance(source, str):
encoded_src = "'%s'" % escape(source)
else:
try:
encoded_src = "'" + str(source) + "'"
except:
- raise ValueError('source type is not valid')
+ raise ValueError("source type is not valid")
return encoded_src
- def render_js(self, field_id, selected=''):
+ def render_js(self, field_id, selected=""):
source = self.encode_source(self.source)
edit_source = self.encode_source(self.edit_source)
- dct = {'source': mark_safe(source),
- 'edit_source': mark_safe(edit_source),
- 'selected': selected,
- 'safe_field_id': slugify(field_id).replace('-', '_'),
- 'field_id': field_id}
+ dct = {
+ "source": mark_safe(source),
+ "edit_source": mark_safe(edit_source),
+ "selected": selected,
+ "safe_field_id": slugify(field_id).replace("-", "_"),
+ "field_id": field_id,
+ }
if self.options:
- dct['options'] = mark_safe('%s' % self.options)
+ dct["options"] = mark_safe("%s" % self.options)
js = loader.get_template(self.js_template).render(dct)
return js
def render(self, name, value, attrs=None, renderer=None):
- attrs_hidden = self.build_attrs(attrs, {'name': name})
+ attrs_hidden = self.build_attrs(attrs, {"name": name})
attrs_select = self.build_attrs(attrs)
- attrs_select['placeholder'] = _("Search...")
- selected = ''
+ attrs_select["placeholder"] = _("Search...")
+ selected = ""
if value:
hiddens = []
selects = []
if type(value) not in (list, tuple):
values = str(escape(smart_text(value)))
- values = values.replace('[', '').replace(']', '')
- values = values.split(',')
+ values = values.replace("[", "").replace("]", "")
+ values = values.split(",")
else:
values = []
for v in value:
- values += v.split(',')
+ values += v.split(",")
for v in values:
if not v:
continue
@@ -999,29 +1063,44 @@ class JQueryPersonOrganization(forms.TextInput):
selects.pop()
hiddens.pop()
if hiddens and selects:
- attrs_hidden['value'] = hiddens[0]
- attrs_select['value'] = selects[0]
- if 'id' not in self.attrs:
- attrs_hidden['id'] = 'id_%s' % name
- attrs_select['id'] = 'id_select_%s' % name
- if 'class' not in attrs_select:
- attrs_select['class'] = 'autocomplete'
- new = ''
- dct = {'attrs_select': mark_safe(flatatt(attrs_select)),
- 'attrs_hidden': mark_safe(flatatt(attrs_hidden)),
- 'name': name,
- 'js': self.render_js(name, selected),
- 'new': mark_safe(new)}
+ attrs_hidden["value"] = hiddens[0]
+ attrs_select["value"] = selects[0]
+ if "id" not in self.attrs:
+ attrs_hidden["id"] = "id_%s" % name
+ attrs_select["id"] = "id_select_%s" % name
+ if "class" not in attrs_select:
+ attrs_select["class"] = "autocomplete"
+ new = ""
+ dct = {
+ "attrs_select": mark_safe(flatatt(attrs_select)),
+ "attrs_hidden": mark_safe(flatatt(attrs_hidden)),
+ "name": name,
+ "js": self.render_js(name, selected),
+ "new": mark_safe(new),
+ }
html = loader.get_template(self.html_template).render(dct)
return html
class DataTable(Select2Media, forms.RadioSelect):
- def __init__(self, source, form, associated_model, attrs=None,
- table_cols='TABLE_COLS', multiple=False, multiple_cols=None,
- new=False, new_message="", source_full=None,
- multiple_select=False, sortname="__default__",
- col_prefix='', gallery=False, map=False):
+ def __init__(
+ self,
+ source,
+ form,
+ associated_model,
+ attrs=None,
+ table_cols="TABLE_COLS",
+ multiple=False,
+ multiple_cols=None,
+ new=False,
+ new_message="",
+ source_full=None,
+ multiple_select=False,
+ sortname="__default__",
+ col_prefix="",
+ gallery=False,
+ map=False,
+ ):
"""
DataTable widget init.
@@ -1061,14 +1140,14 @@ class DataTable(Select2Media, forms.RadioSelect):
self.user = None
self.gallery = gallery
self.map = map
- if self.col_prefix and not self.col_prefix.endswith('__'):
+ if self.col_prefix and not self.col_prefix.endswith("__"):
self.col_prefix += "__"
def get_cols(self, python=False):
jq_col_names, extra_cols = [], []
col_labels = {}
- slug = getattr(self.associated_model, 'SLUG', None)
- if hasattr(self.associated_model, 'COL_LABELS'):
+ slug = getattr(self.associated_model, "SLUG", None)
+ if hasattr(self.associated_model, "COL_LABELS"):
col_labels = self.associated_model.COL_LABELS
if slug in settings.TABLE_COLS:
col_labels.update(settings.TABLE_COLS[slug])
@@ -1088,24 +1167,24 @@ class DataTable(Select2Media, forms.RadioSelect):
col_names = [col_names]
for col_name in col_names:
field = self.associated_model
- keys = col_name.split('__')
- if '.' in col_name:
- keys = col_name.split('.')
+ keys = col_name.split("__")
+ if "." in col_name:
+ keys = col_name.split(".")
for key in keys:
- if hasattr(field, 'rel') and field.rel:
+ if hasattr(field, "rel") and field.rel:
field = field.rel.to
try:
field = field._meta.get_field(key)
field_verbose_name = field.verbose_name
except (fields.FieldDoesNotExist, AttributeError):
- if hasattr(field, key + '_lbl'):
- field_verbose_name = getattr(field, key + '_lbl')
+ if hasattr(field, key + "_lbl"):
+ field_verbose_name = getattr(field, key + "_lbl")
else:
continue
if field_name:
field_name += "__"
if col_name.startswith(self.col_prefix):
- field_name += col_name[len(self.col_prefix):]
+ field_name += col_name[len(self.col_prefix) :]
else:
field_name += col_name
field_verbose_names.append(str(field_verbose_name))
@@ -1119,27 +1198,27 @@ class DataTable(Select2Media, forms.RadioSelect):
elif col_names and col_names[0] in col_labels:
jq_col_names.append(str(col_labels[col_names[0]]))
else:
- jq_col_names.append(settings.JOINT.join(
- [f for f in field_verbose_names if f]))
+ jq_col_names.append(
+ settings.JOINT.join([f for f in field_verbose_names if f])
+ )
extra_cols.append(field_name)
return jq_col_names, extra_cols
def render(self, name, value, attrs=None, renderer=None):
# t = loader.get_template('blocks/form_flex_snippet.html')
- t = loader.get_template('blocks/bs_form_snippet.html')
+ t = loader.get_template("blocks/bs_form_snippet.html")
if self.user:
form = self.form(user=self.user)
- if self.user.ishtaruser and \
- self.user.ishtaruser.show_field_number():
+ if self.user.ishtaruser and self.user.ishtaruser.show_field_number():
form.show_field_number = True
else:
form = self.form()
- rendered = t.render({'form': form, 'search': True})
+ rendered = t.render({"form": form, "search": True})
dct = {}
if self.new:
model_name = self.associated_model._meta.object_name.lower()
- dct['url_new'] = reverse('new-' + model_name, args=['0'])
- dct['new_message'] = self.new_message
+ dct["url_new"] = reverse("new-" + model_name, args=["0"])
+ dct["new_message"] = self.new_message
col_names, extra_cols = self.get_cols()
@@ -1148,53 +1227,58 @@ class DataTable(Select2Media, forms.RadioSelect):
col_idx.append('"%s"' % k)
col_idx = col_idx and ", ".join(col_idx) or ""
- dct['encoding'] = settings.ENCODING or 'utf-8'
+ dct["encoding"] = settings.ENCODING or "utf-8"
try:
- dct['source'] = str(self.source)
+ dct["source"] = str(self.source)
except NoReverseMatch:
- logger.warning('Cannot resolve source for {} widget'.format(
- self.form))
+ logger.warning("Cannot resolve source for {} widget".format(self.form))
# full CSV export currently disabled
- #if str(self.source_full) and str(self.source_full) != 'None':
+ # if str(self.source_full) and str(self.source_full) != 'None':
# dct['source_full'] = str(self.source_full)
- dct['extra_sources'] = []
- dct['quick_actions'] = []
+ dct["extra_sources"] = []
+ dct["quick_actions"] = []
if self.associated_model:
- dct['current_model'] = self.associated_model
+ dct["current_model"] = self.associated_model
model_name = "{}.{}".format(
- self.associated_model.__module__,
- self.associated_model.__name__)
+ self.associated_model.__module__, self.associated_model.__name__
+ )
for imp in models.ImporterType.objects.filter(
- slug__isnull=False, associated_models__klass=model_name,
- is_template=True).all():
- dct['extra_sources'].append((
- imp.slug, imp.name,
- reverse('get-by-importer', args=[imp.slug])))
+ slug__isnull=False,
+ associated_models__klass=model_name,
+ is_template=True,
+ ).all():
+ dct["extra_sources"].append(
+ (imp.slug, imp.name, reverse("get-by-importer", args=[imp.slug]))
+ )
if hasattr(self.associated_model, "QUICK_ACTIONS"):
- dct['quick_actions'] = \
- self.associated_model.get_quick_actions(user=self.user)
+ dct["quick_actions"] = self.associated_model.get_quick_actions(
+ user=self.user
+ )
source = str(self.source)
- dct.update({'name': name,
- 'col_names': col_names,
- 'extra_cols': extra_cols,
- 'source': source,
- 'col_idx': col_idx,
- 'no_result': str(_("No results")),
- 'loading': str(_("Loading...")),
- 'remove': str(_("Remove")),
- 'sname': name.replace('-', ''),
- 'gallery': self.gallery,
- 'use_map': self.map() if callable(self.map) else self.map,
- 'multiple': self.multiple,
- 'multiple_select': self.multiple_select,
- 'multi_cols': ",".join(('"%d"' % col
- for col in self.multiple_cols))})
- t = loader.get_template('blocks/DataTables.html')
+ dct.update(
+ {
+ "name": name,
+ "col_names": col_names,
+ "extra_cols": extra_cols,
+ "source": source,
+ "col_idx": col_idx,
+ "no_result": str(_("No results")),
+ "loading": str(_("Loading...")),
+ "remove": str(_("Remove")),
+ "sname": name.replace("-", ""),
+ "gallery": self.gallery,
+ "use_map": self.map() if callable(self.map) else self.map,
+ "multiple": self.multiple,
+ "multiple_select": self.multiple_select,
+ "multi_cols": ",".join(('"%d"' % col for col in self.multiple_cols)),
+ }
+ )
+ t = loader.get_template("blocks/DataTables.html")
rendered += t.render(dct)
return mark_safe(rendered)
class RangeInput(NumberInput):
- input_type = 'range'
+ input_type = "range"