*Code wurde PEP-8 gerecht formatiert * Kleine Fehler die der PyCharm Inspector beanstandet wurden korrigiert
319 lines
11 KiB
Python
319 lines
11 KiB
Python
"""
|
|
Created on 08.05.2011
|
|
|
|
@author: christian
|
|
"""
|
|
from django.conf import settings
|
|
from django.forms import widgets
|
|
from django.forms.util import flatatt
|
|
from django.utils import formats
|
|
from django.utils.encoding import force_unicode, force_text
|
|
from django.utils.html import conditional_escape
|
|
from django.utils.http import urlencode
|
|
from django.utils.safestring import mark_safe
|
|
|
|
|
|
class AutoCompleteWidget(widgets.TextInput):
|
|
|
|
def __init__(self, lookup_class, attrs=None, *args, **kwargs):
|
|
self.lookup_class = lookup_class
|
|
self.allow_new = kwargs.pop('allow_new', False)
|
|
self.qs = {}
|
|
super(AutoCompleteWidget, self).__init__(*args, **kwargs)
|
|
if attrs is not None:
|
|
self.attrs = attrs.copy()
|
|
else:
|
|
self.attrs = {}
|
|
|
|
def update_query_parameters(self, qs_dict):
|
|
self.qs.update(qs_dict)
|
|
|
|
def build_attrs(self, extra_attrs=None, **kwargs):
|
|
attrs = super(AutoCompleteWidget, self).build_attrs(extra_attrs, **kwargs) # @IgnorePep8
|
|
url = self.lookup_class.url()
|
|
if self.qs:
|
|
url = '%s?%s' % (url, urlencode(self.qs))
|
|
attrs[u'data-selectable-url'] = url
|
|
attrs[u'data-selectable-type'] = 'text'
|
|
attrs[u'data-selectable-allow-new'] = str(self.allow_new).lower()
|
|
return attrs
|
|
|
|
|
|
class AutoComboboxWidget(AutoCompleteWidget):
|
|
|
|
def build_attrs(self, extra_attrs=None, **kwargs):
|
|
attrs = super(AutoComboboxWidget, self).build_attrs(extra_attrs, **kwargs) # @IgnorePep8
|
|
attrs[u'data-selectable-type'] = 'combobox'
|
|
return attrs
|
|
|
|
|
|
class DateInput(widgets.DateInput):
|
|
input_type = 'date'
|
|
attrs = {'class': 'dateinput'}
|
|
|
|
def __init__(self, attrs=None, date_format='%Y-%m-%d'):
|
|
super(DateInput, self).__init__(attrs)
|
|
if date_format:
|
|
self.format = date_format
|
|
self.manual_format = True
|
|
else:
|
|
self.format = formats.get_format('DATE_INPUT_FORMATS')[0]
|
|
self.manual_format = False
|
|
|
|
|
|
class DateTimeInput(widgets.MultiWidget):
|
|
"""
|
|
A Widget that splits datetime input into two <input type="text"> boxes.
|
|
"""
|
|
|
|
def __init__(self, attrs=None, date_format='%Y-%m-%d', time_format='%H:%M'): # @IgnorePep8
|
|
widgets = (
|
|
DateInput(attrs=attrs, date_format=date_format),
|
|
TimeInput(attrs=attrs, time_format=time_format)
|
|
)
|
|
super(DateTimeInput, self).__init__(widgets, attrs)
|
|
|
|
def decompress(self, value):
|
|
if value:
|
|
return [value.date(), value.time()]
|
|
return [None, None]
|
|
|
|
|
|
class CheckboxInput(widgets.CheckboxInput):
|
|
input_type = 'checkbox'
|
|
is_checkbox = True
|
|
|
|
def render(self, name, value, attrs=None):
|
|
final_attrs = self.build_attrs(attrs, type='checkbox', name=name)
|
|
title = force_text(self.attrs.get('title', ''))
|
|
try:
|
|
result = self.check_test(value)
|
|
except: # Silently catch exceptions
|
|
result = False
|
|
if result:
|
|
final_attrs['checked'] = 'checked'
|
|
if not (value is True or value is False or value is None or value == ''): # @IgnorePep8
|
|
# Only add the 'value' attribute if a value is non-empty.
|
|
final_attrs['value'] = force_unicode(value)
|
|
|
|
return mark_safe(u'<input%s /> %s' % (flatatt(final_attrs), title))
|
|
|
|
|
|
class EmailInput(widgets.TextInput):
|
|
input_type = 'email'
|
|
|
|
|
|
class NumberInput(widgets.TextInput):
|
|
input_type = 'number'
|
|
|
|
def __init__(self, attrs=None):
|
|
widgets.Input.__init__(self, attrs=attrs)
|
|
|
|
|
|
class PhoneInput(widgets.TextInput):
|
|
input_type = 'tel'
|
|
|
|
|
|
class RangeInput(widgets.TextInput):
|
|
input_type = 'range'
|
|
|
|
|
|
class ReCaptchaInput(widgets.Widget):
|
|
"""
|
|
Der HTML Code von Googles ReCaptcha als Form Widget
|
|
"""
|
|
recaptcha_challenge_name = 'recaptcha_challenge_field'
|
|
recaptcha_response_name = 'recaptcha_response_field'
|
|
|
|
def render(self, name, value, attrs=None):
|
|
javascript = u"""
|
|
<script type="text/javascript">var RecaptchaOptions = {theme :
|
|
'%(theme)s'};</script><script type="text/javascript"
|
|
src="https://www.google.com/recaptcha/api/challenge?k=%(public_key)s">
|
|
</script><noscript><iframe
|
|
src="https://www.google.com/recaptcha/api/noscript?k=%(public_key)s"
|
|
height="300" width="500" frameborder="0"></iframe><br /><textarea
|
|
name="recaptcha_challenge_field" rows="3" cols="40"></textarea><input
|
|
type="hidden" name="recaptcha_response_field" value="manual_challenge">
|
|
</noscript>"""
|
|
return mark_safe(javascript % {'public_key':
|
|
settings.RECAPTCHA_PUBLIC_KEY, 'theme': 'red'})
|
|
|
|
def value_from_datadict(self, data, files, name):
|
|
return [data.get(self.recaptcha_challenge_name, None),
|
|
data.get(self.recaptcha_response_name, None)]
|
|
|
|
|
|
class SelectableMultiWidget(widgets.MultiWidget):
|
|
|
|
def update_query_parameters(self, qs_dict):
|
|
self.widgets[0].update_query_parameters(qs_dict)
|
|
|
|
|
|
class Textarea(widgets.Widget):
|
|
|
|
def __init__(self, attrs=None):
|
|
# The 'rows' and 'cols' attributes are required for HTML correctness.
|
|
default_attrs = {'cols': '40', 'rows': '10'}
|
|
if attrs:
|
|
default_attrs.update(attrs)
|
|
super(Textarea, self).__init__(default_attrs)
|
|
|
|
def render(self, name, value, attrs=None):
|
|
value = '' if value is None else value
|
|
final_attrs = self.build_attrs(attrs, name=name)
|
|
return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs),
|
|
conditional_escape(force_unicode(value))))
|
|
|
|
|
|
class TextInput(widgets.TextInput):
|
|
pass
|
|
|
|
|
|
class TimeInput(widgets.TimeInput):
|
|
input_type = 'time'
|
|
|
|
def __init__(self, attrs=None, time_format='%H:%M'):
|
|
default_attrs = {'maxlength': 5, 'size': 5}
|
|
if attrs:
|
|
default_attrs.update(attrs)
|
|
super(TimeInput, self).__init__(default_attrs)
|
|
|
|
if time_format:
|
|
self.format = time_format
|
|
self.manual_format = True
|
|
else:
|
|
self.format = formats.get_format('TIME_INPUT_FORMATS')[0]
|
|
self.manual_format = False
|
|
|
|
|
|
class URLInput(widgets.Input):
|
|
input_type = 'url'
|
|
|
|
|
|
class LookupMultipleHiddenInput(widgets.MultipleHiddenInput):
|
|
|
|
def __init__(self, lookup_class, *args, **kwargs):
|
|
self.lookup_class = lookup_class
|
|
super(LookupMultipleHiddenInput, self).__init__(*args, **kwargs)
|
|
|
|
def render(self, name, value, attrs=None, choices=()):
|
|
lookup = self.lookup_class()
|
|
value = [] if value is None else value
|
|
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
|
|
id_ = final_attrs.get('id', None)
|
|
inputs = []
|
|
model = getattr(self.lookup_class, 'model', None)
|
|
for i, v in enumerate(value):
|
|
item = None
|
|
if model and isinstance(v, model):
|
|
item = v
|
|
v = lookup.get_item_id(item)
|
|
input_attrs = dict(value=force_unicode(v), **final_attrs)
|
|
if id_:
|
|
# An ID attribute was given. Add a numeric index as a suffix
|
|
# so that the inputs don't all have the same ID attribute.
|
|
input_attrs['id'] = '%s_%s' % (id_, i)
|
|
if v:
|
|
item = item or lookup.get_item(v)
|
|
input_attrs['title'] = lookup.get_item_value(item)
|
|
inputs.append(u'<input%s />' % flatatt(input_attrs))
|
|
return mark_safe(u'\n'.join(inputs))
|
|
|
|
def build_attrs(self, extra_attrs=None, **kwargs):
|
|
attrs = super(LookupMultipleHiddenInput, self).build_attrs(extra_attrs, **kwargs) # @IgnorePep8
|
|
attrs[u'data-selectable-type'] = 'hidden-multiple'
|
|
return attrs
|
|
|
|
|
|
class AutoCompleteSelectMultipleWidget(SelectableMultiWidget):
|
|
|
|
def __init__(self, lookup_class, *args, **kwargs):
|
|
self.lookup_class = lookup_class
|
|
widgets = [
|
|
AutoCompleteWidget(lookup_class, allow_new=False,
|
|
attrs={u'data-selectable-multiple': 'true'}),
|
|
LookupMultipleHiddenInput(lookup_class)
|
|
]
|
|
super(AutoCompleteSelectMultipleWidget, self).__init__(widgets, *args, **kwargs) # @IgnorePep8
|
|
|
|
def value_from_datadict(self, data, files, name):
|
|
return self.widgets[1].value_from_datadict(data, files, name + '_1')
|
|
|
|
def render(self, name, value, attrs=None):
|
|
if value and not hasattr(value, '__iter__'):
|
|
value = [value]
|
|
value = [u'', value]
|
|
return super(AutoCompleteSelectMultipleWidget, self).render(name, value, attrs) # @IgnorePep8
|
|
|
|
|
|
class AutoComboboxSelectMultipleWidget(SelectableMultiWidget):
|
|
|
|
def __init__(self, lookup_class, *args, **kwargs):
|
|
self.lookup_class = lookup_class
|
|
widgets = [
|
|
AutoComboboxWidget(lookup_class, allow_new=False,
|
|
attrs={u'data-selectable-multiple': 'true'}),
|
|
LookupMultipleHiddenInput(lookup_class)
|
|
]
|
|
super(AutoComboboxSelectMultipleWidget, self).__init__(widgets, *args, **kwargs) # @IgnorePep8
|
|
|
|
def value_from_datadict(self, data, files, name):
|
|
return self.widgets[1].value_from_datadict(data, files, name + '_1')
|
|
|
|
def render(self, name, value, attrs=None):
|
|
if value and not hasattr(value, '__iter__'):
|
|
value = [value]
|
|
value = [u'', value]
|
|
return super(AutoComboboxSelectMultipleWidget, self).render(name, value, attrs) # @IgnorePep8
|
|
|
|
|
|
class AutoCompleteSelectWidget(SelectableMultiWidget):
|
|
|
|
def __init__(self, lookup_class, *args, **kwargs):
|
|
self.lookup_class = lookup_class
|
|
self.allow_new = kwargs.pop('allow_new', False)
|
|
widget_set = [
|
|
AutoCompleteWidget(lookup_class, allow_new=self.allow_new),
|
|
widgets.HiddenInput(attrs={u'data-selectable-type': 'hidden'})
|
|
]
|
|
super(AutoCompleteSelectWidget, self).__init__(widget_set, *args, **kwargs) # @IgnorePep8
|
|
|
|
def decompress(self, value):
|
|
if value:
|
|
lookup = self.lookup_class()
|
|
model = getattr(self.lookup_class, 'model', None)
|
|
if model and isinstance(value, model):
|
|
item = value
|
|
value = lookup.get_item_id(item)
|
|
else:
|
|
item = lookup.get_item(value)
|
|
item_value = lookup.get_item_value(item)
|
|
return [item_value, value]
|
|
return [None, None]
|
|
|
|
|
|
class AutoComboboxSelectWidget(SelectableMultiWidget):
|
|
|
|
def __init__(self, lookup_class, *args, **kwargs):
|
|
self.lookup_class = lookup_class
|
|
self.allow_new = kwargs.pop('allow_new', False)
|
|
widget_set = [
|
|
AutoComboboxWidget(lookup_class, allow_new=self.allow_new),
|
|
widgets.HiddenInput(attrs={u'data-selectable-type': 'hidden'})
|
|
]
|
|
super(AutoComboboxSelectWidget, self).__init__(widget_set, *args, **kwargs) # @IgnorePep8
|
|
|
|
def decompress(self, value):
|
|
if value:
|
|
lookup = self.lookup_class()
|
|
model = getattr(self.lookup_class, 'model', None)
|
|
if model and isinstance(value, model):
|
|
item = value
|
|
value = lookup.get_item_id(item)
|
|
else:
|
|
item = lookup.get_item(value)
|
|
item_value = lookup.get_item_value(item)
|
|
return [item_value, value]
|
|
return [None, None]
|