summaryrefslogtreecommitdiff
path: root/django/contrib/admin
diff options
context:
space:
mode:
Diffstat (limited to 'django/contrib/admin')
-rw-r--r--django/contrib/admin/filterspecs.py59
-rw-r--r--django/contrib/admin/media/css/rtl.css46
-rw-r--r--django/contrib/admin/media/js/admin/CollapsedFieldsets.js8
-rw-r--r--django/contrib/admin/media/js/admin/DateTimeShortcuts.js23
-rw-r--r--django/contrib/admin/media/js/core.js19
-rw-r--r--django/contrib/admin/templates/admin/base.html5
-rw-r--r--django/contrib/admin/templates/admin/filters.html3
-rw-r--r--django/contrib/admin/templates/admin/pagination.html3
-rw-r--r--django/contrib/admin/templates/admin/search_form.html2
-rw-r--r--django/contrib/admin/templates/registration/password_reset_email.html2
-rw-r--r--django/contrib/admin/templatetags/admin_list.py2
-rw-r--r--django/contrib/admin/templatetags/admin_modify.py13
-rw-r--r--django/contrib/admin/views/main.py2
13 files changed, 154 insertions, 33 deletions
diff --git a/django/contrib/admin/filterspecs.py b/django/contrib/admin/filterspecs.py
index 0284f13114..25376be12a 100644
--- a/django/contrib/admin/filterspecs.py
+++ b/django/contrib/admin/filterspecs.py
@@ -11,18 +11,18 @@ import datetime
class FilterSpec(object):
filter_specs = []
- def __init__(self, f, request, params):
+ def __init__(self, f, request, params, model):
self.field = f
self.params = params
def register(cls, test, factory):
- cls.filter_specs.append( (test, factory) )
+ cls.filter_specs.append((test, factory))
register = classmethod(register)
- def create(cls, f, request, params):
+ def create(cls, f, request, params, model):
for test, factory in cls.filter_specs:
if test(f):
- return factory(f, request, params)
+ return factory(f, request, params, model)
create = classmethod(create)
def has_output(self):
@@ -48,8 +48,8 @@ class FilterSpec(object):
return "".join(t)
class RelatedFilterSpec(FilterSpec):
- def __init__(self, f, request, params):
- super(RelatedFilterSpec, self).__init__(f, request, params)
+ def __init__(self, f, request, params, model):
+ super(RelatedFilterSpec, self).__init__(f, request, params, model)
if isinstance(f, models.ManyToManyField):
self.lookup_title = f.rel.to._meta.verbose_name
else:
@@ -71,31 +71,31 @@ class RelatedFilterSpec(FilterSpec):
for val in self.lookup_choices:
pk_val = getattr(val, self.field.rel.to._meta.pk.attname)
yield {'selected': self.lookup_val == str(pk_val),
- 'query_string': cl.get_query_string( {self.lookup_kwarg: pk_val}),
+ 'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}),
'display': val}
FilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)
class ChoicesFilterSpec(FilterSpec):
- def __init__(self, f, request, params):
- super(ChoicesFilterSpec, self).__init__(f, request, params)
+ def __init__(self, f, request, params, model):
+ super(ChoicesFilterSpec, self).__init__(f, request, params, model)
self.lookup_kwarg = '%s__exact' % f.name
self.lookup_val = request.GET.get(self.lookup_kwarg, None)
def choices(self, cl):
yield {'selected': self.lookup_val is None,
- 'query_string': cl.get_query_string( {}, [self.lookup_kwarg]),
+ 'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
'display': _('All')}
for k, v in self.field.choices:
yield {'selected': str(k) == self.lookup_val,
- 'query_string': cl.get_query_string( {self.lookup_kwarg: k}),
+ 'query_string': cl.get_query_string({self.lookup_kwarg: k}),
'display': v}
FilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)
class DateFieldFilterSpec(FilterSpec):
- def __init__(self, f, request, params):
- super(DateFieldFilterSpec, self).__init__(f, request, params)
+ def __init__(self, f, request, params, model):
+ super(DateFieldFilterSpec, self).__init__(f, request, params, model)
self.field_generic = '%s__' % self.field.name
@@ -123,14 +123,14 @@ class DateFieldFilterSpec(FilterSpec):
def choices(self, cl):
for title, param_dict in self.links:
yield {'selected': self.date_params == param_dict,
- 'query_string': cl.get_query_string( param_dict, self.field_generic),
+ 'query_string': cl.get_query_string(param_dict, self.field_generic),
'display': title}
FilterSpec.register(lambda f: isinstance(f, models.DateField), DateFieldFilterSpec)
class BooleanFieldFilterSpec(FilterSpec):
- def __init__(self, f, request, params):
- super(BooleanFieldFilterSpec, self).__init__(f, request, params)
+ def __init__(self, f, request, params, model):
+ super(BooleanFieldFilterSpec, self).__init__(f, request, params, model)
self.lookup_kwarg = '%s__exact' % f.name
self.lookup_kwarg2 = '%s__isnull' % f.name
self.lookup_val = request.GET.get(self.lookup_kwarg, None)
@@ -142,11 +142,34 @@ class BooleanFieldFilterSpec(FilterSpec):
def choices(self, cl):
for k, v in ((_('All'), None), (_('Yes'), '1'), (_('No'), '0')):
yield {'selected': self.lookup_val == v and not self.lookup_val2,
- 'query_string': cl.get_query_string( {self.lookup_kwarg: v}, [self.lookup_kwarg2]),
+ 'query_string': cl.get_query_string({self.lookup_kwarg: v}, [self.lookup_kwarg2]),
'display': k}
if isinstance(self.field, models.NullBooleanField):
yield {'selected': self.lookup_val2 == 'True',
- 'query_string': cl.get_query_string( {self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]),
+ 'query_string': cl.get_query_string({self.lookup_kwarg2: 'True'}, [self.lookup_kwarg]),
'display': _('Unknown')}
FilterSpec.register(lambda f: isinstance(f, models.BooleanField) or isinstance(f, models.NullBooleanField), BooleanFieldFilterSpec)
+
+# This should be registered last, because it's a last resort. For example,
+# if a field is eligible to use the BooleanFieldFilterSpec, that'd be much
+# more appropriate, and the AllValuesFilterSpec won't get used for it.
+class AllValuesFilterSpec(FilterSpec):
+ def __init__(self, f, request, params, model):
+ super(AllValuesFilterSpec, self).__init__(f, request, params, model)
+ self.lookup_val = request.GET.get(f.name, None)
+ self.lookup_choices = model._meta.admin.manager.distinct().order_by(f.name).values(f.name)
+
+ def title(self):
+ return self.field.verbose_name
+
+ def choices(self, cl):
+ yield {'selected': self.lookup_val is None,
+ 'query_string': cl.get_query_string({}, [self.field.name]),
+ 'display': _('All')}
+ for val in self.lookup_choices:
+ val = str(val[self.field.name])
+ yield {'selected': self.lookup_val == val,
+ 'query_string': cl.get_query_string({self.field.name: val}),
+ 'display': val}
+FilterSpec.register(lambda f: True, AllValuesFilterSpec)
diff --git a/django/contrib/admin/media/css/rtl.css b/django/contrib/admin/media/css/rtl.css
new file mode 100644
index 0000000000..c29391cabf
--- /dev/null
+++ b/django/contrib/admin/media/css/rtl.css
@@ -0,0 +1,46 @@
+body { direction: rtl; }
+
+/* login styles */
+
+.login .form-row { float:right; }
+.login .form-row label { float:right; padding-left:0.5em; padding-right:0; text-align:left;}
+.login .submit-row { clear:both; padding:1em 9.4em 0 0; }
+
+
+/* global styles */
+th { text-align: right; }
+.module h2, .module caption { text-align: right; }
+.addlink, .changelink { padding-left:0px; padding-right:12px; background-position:100% 0.2em; }
+.deletelink { padding-left:0px; padding-right:12px; background-position:100% 0.25em; }
+.object-tools { float:left; }
+
+
+/* layout styles */
+#user-tools { right:auto; left:0; text-align:left; }
+div.breadcrumbs { text-align:right; }
+#content-main { float:right;}
+#content-related { float:left; margin-left:-19em; margin-right:auto;}
+.colMS { margin-left:20em !important; margin-right:10px !important;}
+
+/* dashboard styles */
+.dashboard .module table td a { padding-left:.6em; padding-right:12px; }
+
+/* changelists styles */
+.change-list .filtered { background:white url(../img/admin/changelist-bg_rtl.gif) top left repeat-y !important; }
+.change-list .filtered table { border-left:1px solid #ddd; border-right:0px none; }
+#changelist-filter { right:auto; left:0; border-left:0px none; border-right:1px solid #ddd;}
+.change-list .filtered table, .change-list .filtered .paginator, .filtered #toolbar, .filtered div.xfull { margin-right:0px !important; margin-left:160px !important; }
+#changelist-filter li.selected { border-left:0px none; padding-left:0px; margin-left:0; border-right:5px solid #ccc; padding-right:5px;margin-right:-10px; }
+
+/* fomrs styles */
+.aligned label { padding:0 0 3px 1em; float:right; }
+.submit-row { text-align: left }
+.vDateField, .vTimeField { margin-left:2px; }
+
+/* widget styles */
+.calendarnav-previous { top:0; left:auto; right:0; }
+.calendarnav-next { top:0; right:auto; left:0;}
+.calendar caption, .calendarbox h2 { text-align:center; }
+
+.selector { float: right;}
+.selector .selector-filter { text-align: right;}
diff --git a/django/contrib/admin/media/js/admin/CollapsedFieldsets.js b/django/contrib/admin/media/js/admin/CollapsedFieldsets.js
index 0b3ad9e421..97f0a68d04 100644
--- a/django/contrib/admin/media/js/admin/CollapsedFieldsets.js
+++ b/django/contrib/admin/media/js/admin/CollapsedFieldsets.js
@@ -31,7 +31,7 @@ var CollapsedFieldsets = {
collapse_link.id = 'fieldsetcollapser' + i;
collapse_link.onclick = new Function('CollapsedFieldsets.show('+i+'); return false;');
collapse_link.href = '#';
- collapse_link.innerHTML = 'Show';
+ collapse_link.innerHTML = gettext('Show');
var h2 = fs.getElementsByTagName('h2')[0];
h2.appendChild(document.createTextNode(' ('));
h2.appendChild(collapse_link);
@@ -60,7 +60,7 @@ var CollapsedFieldsets = {
// Toggle the "Show" link to a "Hide" link
var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index);
collapse_link.onclick = new Function('CollapsedFieldsets.hide('+fieldset_index+'); return false;');
- collapse_link.innerHTML = 'Hide';
+ collapse_link.innerHTML = gettext('Hide');
},
hide: function(fieldset_index) {
var fs = document.getElementsByTagName('fieldset')[fieldset_index];
@@ -69,9 +69,9 @@ var CollapsedFieldsets = {
// Toggle the "Hide" link to a "Show" link
var collapse_link = document.getElementById('fieldsetcollapser' + fieldset_index);
collapse_link.onclick = new Function('CollapsedFieldsets.show('+fieldset_index+'); return false;');
- collapse_link.innerHTML = 'Show';
+ collapse_link.innerHTML = gettext('Show');
},
-
+
uncollapse_all: function() {
var fieldsets = document.getElementsByTagName('fieldset');
for (var i=0; i<fieldsets.length; i++) {
diff --git a/django/contrib/admin/media/js/admin/DateTimeShortcuts.js b/django/contrib/admin/media/js/admin/DateTimeShortcuts.js
index 28511f76c6..ed99c6103d 100644
--- a/django/contrib/admin/media/js/admin/DateTimeShortcuts.js
+++ b/django/contrib/admin/media/js/admin/DateTimeShortcuts.js
@@ -69,7 +69,16 @@ var DateTimeShortcuts = {
var clock_box = document.createElement('div');
clock_box.style.display = 'none';
clock_box.style.position = 'absolute';
- clock_box.style.left = findPosX(clock_link) + 17 + 'px';
+ if (getStyle(document.body,'direction')!='rtl') {
+ clock_box.style.left = findPosX(clock_link) + 17 + 'px';
+ }
+ else {
+ // since style's width is in em, it'd be tough to calculate
+ // px value of it. let's use an estimated px for now
+ // TODO: IE returns wrong value for findPosX when in rtl mode
+ // (it returns as it was left aligned), needs to be fixed.
+ clock_box.style.left = findPosX(clock_link) - 110 + 'px';
+ }
clock_box.style.top = findPosY(clock_link) - 30 + 'px';
clock_box.className = 'clockbox module';
clock_box.setAttribute('id', DateTimeShortcuts.clockDivName + num);
@@ -140,7 +149,17 @@ var DateTimeShortcuts = {
var cal_box = document.createElement('div');
cal_box.style.display = 'none';
cal_box.style.position = 'absolute';
- cal_box.style.left = findPosX(cal_link) + 17 + 'px';
+ // is it left-to-right or right-to-left layout ?
+ if (getStyle(document.body,'direction')!='rtl') {
+ cal_box.style.left = findPosX(cal_link) + 17 + 'px';
+ }
+ else {
+ // since style's width is in em, it'd be tough to calculate
+ // px value of it. let's use an estimated px for now
+ // TODO: IE returns wrong value for findPosX when in rtl mode
+ // (it returns as it was left aligned), needs to be fixed.
+ cal_box.style.left = findPosX(cal_link) - 180 + 'px';
+ }
cal_box.style.top = findPosY(cal_link) - 75 + 'px';
cal_box.className = 'calendarbox module';
cal_box.setAttribute('id', DateTimeShortcuts.calendarDivName1 + num);
diff --git a/django/contrib/admin/media/js/core.js b/django/contrib/admin/media/js/core.js
index 1c8f678773..8eba69c9bb 100644
--- a/django/contrib/admin/media/js/core.js
+++ b/django/contrib/admin/media/js/core.js
@@ -135,4 +135,21 @@ String.prototype.pad_left = function(pad_length, pad_string) {
new_string = pad_string + new_string;
}
return new_string;
-} \ No newline at end of file
+}
+
+// ----------------------------------------------------------------------------
+// Get the computed style for and element
+// ----------------------------------------------------------------------------
+function getStyle(oElm, strCssRule){
+ var strValue = "";
+ if(document.defaultView && document.defaultView.getComputedStyle){
+ strValue = document.defaultView.getComputedStyle(oElm, "").getPropertyValue(strCssRule);
+ }
+ else if(oElm.currentStyle){
+ strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
+ return p1.toUpperCase();
+ });
+ strValue = oElm.currentStyle[strCssRule];
+ }
+ return strValue;
+}
diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html
index a8c1c9c101..e7f1c7e5a9 100644
--- a/django/contrib/admin/templates/admin/base.html
+++ b/django/contrib/admin/templates/admin/base.html
@@ -1,8 +1,9 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" lang="{{ LANGUAGE_CODE }}" xml:lang="{{ LANGUAGE_CODE }}">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="{{ LANGUAGE_CODE }}" xml:lang="{{ LANGUAGE_CODE }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
<head>
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% load adminmedia %}{% admin_media_prefix %}css/base.css{% endblock %}" />
+{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% admin_media_prefix %}css/rtl.css{% endblock %}" />{% endif %}
{% block extrastyle %}{% endblock %}
{% block extrahead %}{% endblock %}
</head>
@@ -20,7 +21,7 @@
{% block branding %}{% endblock %}
</div>
{% if not user.is_anonymous %}{% if user.is_staff %}
- <div id="user-tools">{% trans 'Welcome,' %} <strong>{% if user.first_name %}{{ user.first_name }}{% else %}{{ user.username }}{% endif %}</strong>. {% block userlinks %}<a href="doc/">{% trans 'Documentation' %}</a> / <a href="password_change/">{% trans 'Change password' %}</a> / <a href="logout/">{% trans 'Log out' %}</a>{% endblock %}</div>
+ <div id="user-tools">{% trans 'Welcome,' %} <strong>{% if user.first_name %}{{ user.first_name|escape }}{% else %}{{ user.username }}{% endif %}</strong>. {% block userlinks %}<a href="doc/">{% trans 'Documentation' %}</a> / <a href="password_change/">{% trans 'Change password' %}</a> / <a href="logout/">{% trans 'Log out' %}</a>{% endblock %}</div>
{% endif %}{% endif %}
{% block nav-global %}{% endblock %}
</div>
diff --git a/django/contrib/admin/templates/admin/filters.html b/django/contrib/admin/templates/admin/filters.html
index 93c2f65b15..3ca763cce3 100644
--- a/django/contrib/admin/templates/admin/filters.html
+++ b/django/contrib/admin/templates/admin/filters.html
@@ -1,6 +1,7 @@
{% load admin_list %}
+{% load i18n %}
{% if cl.has_filters %}<div id="changelist-filter">
-<h2>Filter</h2>
+<h2>{% trans 'Filter' %}</h2>
{% for spec in cl.filter_specs %}
{% filter cl spec %}
{% endfor %}</div>{% endif %}
diff --git a/django/contrib/admin/templates/admin/pagination.html b/django/contrib/admin/templates/admin/pagination.html
index 64b1b1a3dd..7694e4c5b0 100644
--- a/django/contrib/admin/templates/admin/pagination.html
+++ b/django/contrib/admin/templates/admin/pagination.html
@@ -1,4 +1,5 @@
{% load admin_list %}
+{% load i18n %}
<p class="paginator">
{% if pagination_required %}
{% for i in page_range %}
@@ -6,5 +7,5 @@
{% endfor %}
{% endif %}
{{ cl.result_count }} {% ifequal cl.result_count 1 %}{{ cl.opts.verbose_name }}{% else %}{{ cl.opts.verbose_name_plural }}{% endifequal %}
-{% if show_all_url %}&nbsp;&nbsp;<a href="{{ show_all_url }}" class="showall">Show all</a>{% endif %}
+{% if show_all_url %}&nbsp;&nbsp;<a href="{{ show_all_url }}" class="showall">{% trans 'Show all' %}</a>{% endif %}
</p>
diff --git a/django/contrib/admin/templates/admin/search_form.html b/django/contrib/admin/templates/admin/search_form.html
index 24eced9ef9..d9126c3ec5 100644
--- a/django/contrib/admin/templates/admin/search_form.html
+++ b/django/contrib/admin/templates/admin/search_form.html
@@ -7,7 +7,7 @@
<input type="text" size="40" name="{{ search_var }}" value="{{ cl.query|escape }}" id="searchbar" />
<input type="submit" value="{% trans 'Go' %}" />
{% if show_result_count %}
- <span class="small quiet">{{ cl.result_count }} result{{ cl.result_count|pluralize }} (<a href="?">{{ cl.full_result_count }} total</a>)</span>
+ <span class="small quiet">{% blocktrans count cl.result_count as counter %}1 result{% plural %}{{ counter }} results{% endblocktrans %} (<a href="?">{% blocktrans with cl.full_result_count as full_result_count %}{{ full_result_count }} total{% endblocktrans %}</a>)</span>
{% endif %}
{% for pair in cl.params.items %}
{% ifnotequal pair.0 search_var %}<input type="hidden" name="{{ pair.0|escape }}" value="{{ pair.1|escape }}"/>{% endifnotequal %}
diff --git a/django/contrib/admin/templates/registration/password_reset_email.html b/django/contrib/admin/templates/registration/password_reset_email.html
index b7f31e484c..f765dd0670 100644
--- a/django/contrib/admin/templates/registration/password_reset_email.html
+++ b/django/contrib/admin/templates/registration/password_reset_email.html
@@ -1,6 +1,6 @@
{% load i18n %}
{% trans "You're receiving this e-mail because you requested a password reset" %}
-{% trans "for your user account at %(site_name)s" %}.
+{% blocktrans %}for your user account at {{ site_name }}{% endblocktrans %}.
{% blocktrans %}Your new password is: {{ new_password }}{% endblocktrans %}
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py
index d5f8df9dfd..0e550dd471 100644
--- a/django/contrib/admin/templatetags/admin_list.py
+++ b/django/contrib/admin/templatetags/admin_list.py
@@ -131,7 +131,7 @@ def items_for_result(cl, result):
if isinstance(f.rel, models.ManyToOneRel):
if field_val is not None:
- result_repr = getattr(result, f.name)
+ result_repr = escape(getattr(result, f.name))
else:
result_repr = EMPTY_CHANGELIST_VALUE
# Dates and times are special: They're formatted in a certain way.
diff --git a/django/contrib/admin/templatetags/admin_modify.py b/django/contrib/admin/templatetags/admin_modify.py
index 9f646214ce..2d34452f52 100644
--- a/django/contrib/admin/templatetags/admin_modify.py
+++ b/django/contrib/admin/templatetags/admin_modify.py
@@ -18,6 +18,19 @@ def class_name_to_underscored(name):
return '_'.join([s.lower() for s in word_re.findall(name)[:-1]])
def include_admin_script(script_path):
+ """
+ Returns an HTML script element for including a script from the admin
+ media url.
+
+ Example usage::
+
+ {% include_admin_script js/calendar.js %}
+
+ could return::
+
+ <script type="text/javascript" src="/media/admin/js/calendar.js">
+ """
+
return '<script type="text/javascript" src="%s%s"></script>' % (settings.ADMIN_MEDIA_PREFIX, script_path)
include_admin_script = register.simple_tag(include_admin_script)
diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py
index af55587d23..ea7aeb490b 100644
--- a/django/contrib/admin/views/main.py
+++ b/django/contrib/admin/views/main.py
@@ -574,7 +574,7 @@ class ChangeList(object):
filter_fields = [self.lookup_opts.get_field(field_name) \
for field_name in self.lookup_opts.admin.list_filter]
for f in filter_fields:
- spec = FilterSpec.create(f, request, self.params)
+ spec = FilterSpec.create(f, request, self.params, self.model)
if spec and spec.has_output():
filter_specs.append(spec)
return filter_specs, bool(filter_specs)