""" Form Widget classes specific to the Django admin site. """ from __future__ import absolute_import from itertools import chain from django import forms try: from django.forms.widgets import ChoiceWidget as RadioChoiceInput except: from django.forms.widgets import RadioFieldRenderer, RadioChoiceInput from django.utils.encoding import force_text from django.utils.safestring import mark_safe from django.utils.html import conditional_escape from django.utils.translation import ugettext as _ from .util import vendor class AdminDateWidget(forms.DateInput): @property def media(self): return vendor('datepicker.js', 'datepicker.css', 'xadmin.widget.datetime.js') def __init__(self, attrs=None, format=None): final_attrs = {'class': 'date-field form-control', 'size': '10'} if attrs is not None: final_attrs.update(attrs) super(AdminDateWidget, self).__init__(attrs=final_attrs, format=format) def render(self, name, value, attrs=None, renderer=None): input_html = super(AdminDateWidget, self).render(name, value, attrs, renderer) return mark_safe('
%s' '
' % (input_html, _(u'Today'))) class AdminTimeWidget(forms.TimeInput): @property def media(self): return vendor('datepicker.js', 'clockpicker.js', 'clockpicker.css', 'xadmin.widget.datetime.js') def __init__(self, attrs=None, format=None): final_attrs = {'class': 'time-field form-control', 'size': '8'} if attrs is not None: final_attrs.update(attrs) super(AdminTimeWidget, self).__init__(attrs=final_attrs, format=format) def render(self, name, value, attrs=None, renderer=None): input_html = super(AdminTimeWidget, self).render(name, value, attrs, renderer) return mark_safe('
' '%s
' % (input_html, _(u'Now'))) class AdminSelectWidget(forms.Select): @property def media(self): return vendor('select.js', 'select.css', 'xadmin.widget.select.js') class AdminSplitDateTime(forms.SplitDateTimeWidget): """ A SplitDateTime Widget that has some admin-specific styling. """ def __init__(self, attrs=None): widgets = [AdminDateWidget, AdminTimeWidget] # Note that we're calling MultiWidget, not SplitDateTimeWidget, because # we want to define widgets. forms.MultiWidget.__init__(self, widgets, attrs) def render(self, name, value, attrs=None, renderer=None): input_html = [ht for ht in super(AdminSplitDateTime, self).render(name, value, attrs, renderer).replace('>\n
%s' '
' '
' '%s
' % (input_html[0], _(u'Today'), input_html[1], _(u'Now'))) def format_output(self, rendered_widgets): return mark_safe(u'
%s%s
' % (rendered_widgets[0], rendered_widgets[1])) class AdminRadioInput(RadioChoiceInput): def render(self, name=None, value=None, attrs=None, choices=()): name = name or self.name value = value or self.value attrs = attrs or self.attrs attrs['class'] = attrs.get('class', '').replace('form-control', '') if 'id' in self.attrs: label_for = ' for="%s_%s"' % (self.attrs['id'], self.index) else: label_for = '' choice_label = conditional_escape(force_text(self.choice_label)) if attrs.get('inline', False): return mark_safe(u'%s %s' % (label_for, self.tag(), choice_label)) else: return mark_safe(u'
%s %s
' % (label_for, self.tag(), choice_label)) class AdminRadioFieldRenderer(forms.RadioSelect): def __iter__(self): for i, choice in enumerate(self.choices): yield AdminRadioInput(self.name, self.value, self.attrs.copy(), choice, i) def __getitem__(self, idx): choice = self.choices[idx] # Let the IndexError propogate return AdminRadioInput(self.name, self.value, self.attrs.copy(), choice, idx) def render(self): return mark_safe(u'\n'.join([force_text(w) for w in self])) class AdminRadioSelect(forms.RadioSelect): renderer = AdminRadioFieldRenderer class AdminCheckboxSelect(forms.CheckboxSelectMultiple): def render(self, name, value, attrs=None, choices=()): if value is None: value = [] has_id = attrs and 'id' in attrs final_attrs = self.build_attrs(attrs, extra_attrs={'name': name}) output = [] # Normalize to strings str_values = set([force_text(v) for v in value]) for i, (option_value, option_label) in enumerate(chain(self.choices, choices)): # If an ID attribute was given, add a numeric index as a suffix, # so that the checkboxes don't all have the same ID attribute. if has_id: final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i)) label_for = u' for="%s"' % final_attrs['id'] else: label_for = '' cb = forms.CheckboxInput( final_attrs, check_test=lambda value: value in str_values) option_value = force_text(option_value) rendered_cb = cb.render(name, option_value) option_label = conditional_escape(force_text(option_label)) if final_attrs.get('inline', False): output.append(u'%s %s' % (label_for, rendered_cb, option_label)) else: output.append(u'
%s %s
' % (label_for, rendered_cb, option_label)) return mark_safe(u'\n'.join(output)) class AdminSelectMultiple(forms.SelectMultiple): def __init__(self, attrs=None): final_attrs = {'class': 'select-multi'} if attrs is not None: final_attrs.update(attrs) super(AdminSelectMultiple, self).__init__(attrs=final_attrs) class AdminFileWidget(forms.ClearableFileInput): template_with_initial = (u'

%s

' % forms.ClearableFileInput.initial_text) template_with_clear = (u'%s' % forms.ClearableFileInput.clear_checkbox_label) class AdminTextareaWidget(forms.Textarea): def __init__(self, attrs=None): final_attrs = {'class': 'textarea-field'} if attrs is not None: final_attrs.update(attrs) super(AdminTextareaWidget, self).__init__(attrs=final_attrs) class AdminTextInputWidget(forms.TextInput): def __init__(self, attrs=None): final_attrs = {'class': 'text-field'} if attrs is not None: final_attrs.update(attrs) super(AdminTextInputWidget, self).__init__(attrs=final_attrs) class AdminURLFieldWidget(forms.TextInput): def __init__(self, attrs=None): final_attrs = {'class': 'url-field'} if attrs is not None: final_attrs.update(attrs) super(AdminURLFieldWidget, self).__init__(attrs=final_attrs) class AdminIntegerFieldWidget(forms.TextInput): def __init__(self, attrs=None): final_attrs = {'class': 'int-field'} if attrs is not None: final_attrs.update(attrs) super(AdminIntegerFieldWidget, self).__init__(attrs=final_attrs) class AdminCommaSeparatedIntegerFieldWidget(forms.TextInput): def __init__(self, attrs=None): final_attrs = {'class': 'sep-int-field'} if attrs is not None: final_attrs.update(attrs) super(AdminCommaSeparatedIntegerFieldWidget, self).__init__(attrs=final_attrs)