summaryrefslogtreecommitdiffstats
path: root/webapp/django/contrib/admin/widgets.py
diff options
context:
space:
mode:
Diffstat (limited to 'webapp/django/contrib/admin/widgets.py')
-rw-r--r--webapp/django/contrib/admin/widgets.py238
1 files changed, 238 insertions, 0 deletions
diff --git a/webapp/django/contrib/admin/widgets.py b/webapp/django/contrib/admin/widgets.py
new file mode 100644
index 0000000000..2bfbc9715d
--- /dev/null
+++ b/webapp/django/contrib/admin/widgets.py
@@ -0,0 +1,238 @@
+"""
+Form Widget classes specific to the Django admin site.
+"""
+
+import copy
+
+from django import forms
+from django.forms.widgets import RadioFieldRenderer
+from django.forms.util import flatatt
+from django.utils.text import truncate_words
+from django.utils.translation import ugettext as _
+from django.utils.safestring import mark_safe
+from django.utils.encoding import force_unicode
+from django.conf import settings
+
+class FilteredSelectMultiple(forms.SelectMultiple):
+ """
+ A SelectMultiple with a JavaScript filter interface.
+
+ Note that the resulting JavaScript assumes that the SelectFilter2.js
+ library and its dependencies have been loaded in the HTML page.
+ """
+ def __init__(self, verbose_name, is_stacked, attrs=None, choices=()):
+ self.verbose_name = verbose_name
+ self.is_stacked = is_stacked
+ super(FilteredSelectMultiple, self).__init__(attrs, choices)
+
+ def render(self, name, value, attrs=None, choices=()):
+ output = [super(FilteredSelectMultiple, self).render(name, value, attrs, choices)]
+ output.append(u'<script type="text/javascript">addEvent(window, "load", function(e) {')
+ # TODO: "id_" is hard-coded here. This should instead use the correct
+ # API to determine the ID dynamically.
+ output.append(u'SelectFilter.init("id_%s", "%s", %s, "%s"); });</script>\n' % \
+ (name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.ADMIN_MEDIA_PREFIX))
+ return mark_safe(u''.join(output))
+
+class AdminDateWidget(forms.TextInput):
+ class Media:
+ js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
+ settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
+
+ def __init__(self, attrs={}):
+ super(AdminDateWidget, self).__init__(attrs={'class': 'vDateField', 'size': '10'})
+
+class AdminTimeWidget(forms.TextInput):
+ class Media:
+ js = (settings.ADMIN_MEDIA_PREFIX + "js/calendar.js",
+ settings.ADMIN_MEDIA_PREFIX + "js/admin/DateTimeShortcuts.js")
+
+ def __init__(self, attrs={}):
+ super(AdminTimeWidget, self).__init__(attrs={'class': 'vTimeField', 'size': '8'})
+
+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 format_output(self, rendered_widgets):
+ return mark_safe(u'<p class="datetime">%s %s<br />%s %s</p>' % \
+ (_('Date:'), rendered_widgets[0], _('Time:'), rendered_widgets[1]))
+
+class AdminRadioFieldRenderer(RadioFieldRenderer):
+ def render(self):
+ """Outputs a <ul> for this set of radio fields."""
+ return mark_safe(u'<ul%s>\n%s\n</ul>' % (
+ flatatt(self.attrs),
+ u'\n'.join([u'<li>%s</li>' % force_unicode(w) for w in self]))
+ )
+
+class AdminRadioSelect(forms.RadioSelect):
+ renderer = AdminRadioFieldRenderer
+
+class AdminFileWidget(forms.FileInput):
+ """
+ A FileField Widget that shows its current value if it has one.
+ """
+ def __init__(self, attrs={}):
+ super(AdminFileWidget, self).__init__(attrs)
+
+ def render(self, name, value, attrs=None):
+ output = []
+ if value and hasattr(value, "url"):
+ output.append('%s <a target="_blank" href="%s">%s</a> <br />%s ' % \
+ (_('Currently:'), value.url, value, _('Change:')))
+ output.append(super(AdminFileWidget, self).render(name, value, attrs))
+ return mark_safe(u''.join(output))
+
+class ForeignKeyRawIdWidget(forms.TextInput):
+ """
+ A Widget for displaying ForeignKeys in the "raw_id" interface rather than
+ in a <select> box.
+ """
+ def __init__(self, rel, attrs=None):
+ self.rel = rel
+ super(ForeignKeyRawIdWidget, self).__init__(attrs)
+
+ def render(self, name, value, attrs=None):
+ related_url = '../../../%s/%s/' % (self.rel.to._meta.app_label, self.rel.to._meta.object_name.lower())
+ if self.rel.limit_choices_to:
+ url = '?' + '&amp;'.join(['%s=%s' % (k, v) for k, v in self.rel.limit_choices_to.items()])
+ else:
+ url = ''
+ if not attrs.has_key('class'):
+ attrs['class'] = 'vForeignKeyRawIdAdminField' # The JavaScript looks for this hook.
+ output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)]
+ # TODO: "id_" is hard-coded here. This should instead use the correct
+ # API to determine the ID dynamically.
+ output.append('<a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \
+ (related_url, url, name))
+ output.append('<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="Lookup" /></a>' % settings.ADMIN_MEDIA_PREFIX)
+ if value:
+ output.append(self.label_for_value(value))
+ return mark_safe(u''.join(output))
+
+ def label_for_value(self, value):
+ return '&nbsp;<strong>%s</strong>' % \
+ truncate_words(self.rel.to.objects.get(pk=value), 14)
+
+class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
+ """
+ A Widget for displaying ManyToMany ids in the "raw_id" interface rather than
+ in a <select multiple> box.
+ """
+ def __init__(self, rel, attrs=None):
+ super(ManyToManyRawIdWidget, self).__init__(rel, attrs)
+
+ def render(self, name, value, attrs=None):
+ attrs['class'] = 'vManyToManyRawIdAdminField'
+ if value:
+ value = ','.join([str(v) for v in value])
+ else:
+ value = ''
+ return super(ManyToManyRawIdWidget, self).render(name, value, attrs)
+
+ def label_for_value(self, value):
+ return ''
+
+ def value_from_datadict(self, data, files, name):
+ value = data.get(name, None)
+ if value and ',' in value:
+ return data[name].split(',')
+ if value:
+ return [value]
+ return None
+
+ def _has_changed(self, initial, data):
+ if initial is None:
+ initial = []
+ if data is None:
+ data = []
+ if len(initial) != len(data):
+ return True
+ for pk1, pk2 in zip(initial, data):
+ if force_unicode(pk1) != force_unicode(pk2):
+ return True
+ return False
+
+class RelatedFieldWidgetWrapper(forms.Widget):
+ """
+ This class is a wrapper to a given widget to add the add icon for the
+ admin interface.
+ """
+ def __init__(self, widget, rel, admin_site):
+ self.is_hidden = widget.is_hidden
+ self.needs_multipart_form = widget.needs_multipart_form
+ self.attrs = widget.attrs
+ self.choices = widget.choices
+ self.widget = widget
+ self.rel = rel
+ # so we can check if the related object is registered with this AdminSite
+ self.admin_site = admin_site
+
+ def __deepcopy__(self, memo):
+ obj = copy.copy(self)
+ obj.widget = copy.deepcopy(self.widget, memo)
+ obj.attrs = self.widget.attrs
+ memo[id(self)] = obj
+ return obj
+
+ def render(self, name, value, *args, **kwargs):
+ rel_to = self.rel.to
+ related_url = '../../../%s/%s/' % (rel_to._meta.app_label, rel_to._meta.object_name.lower())
+ self.widget.choices = self.choices
+ output = [self.widget.render(name, value, *args, **kwargs)]
+ if rel_to in self.admin_site._registry: # If the related object has an admin interface:
+ # TODO: "id_" is hard-coded here. This should instead use the correct
+ # API to determine the ID dynamically.
+ output.append(u'<a href="%sadd/" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
+ (related_url, name))
+ output.append(u'<img src="%simg/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/></a>' % settings.ADMIN_MEDIA_PREFIX)
+ return mark_safe(u''.join(output))
+
+ def build_attrs(self, extra_attrs=None, **kwargs):
+ "Helper function for building an attribute dictionary."
+ self.attrs = self.widget.build_attrs(extra_attrs=None, **kwargs)
+ return self.attrs
+
+ def value_from_datadict(self, data, files, name):
+ return self.widget.value_from_datadict(data, files, name)
+
+ def _has_changed(self, initial, data):
+ return self.widget._has_changed(initial, data)
+
+ def id_for_label(self, id_):
+ return self.widget.id_for_label(id_)
+
+class AdminTextareaWidget(forms.Textarea):
+ def __init__(self, attrs=None):
+ final_attrs = {'class': 'vLargeTextField'}
+ 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': 'vTextField'}
+ 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': 'vURLField'}
+ 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': 'vIntegerField'}
+ if attrs is not None:
+ final_attrs.update(attrs)
+ super(AdminIntegerFieldWidget, self).__init__(attrs=final_attrs)