diff --git a/django/contrib/admin/static/admin/css/base.css b/django/contrib/admin/static/admin/css/base.css index 47ac79b1d0..66237f4f7c 100644 --- a/django/contrib/admin/static/admin/css/base.css +++ b/django/contrib/admin/static/admin/css/base.css @@ -188,7 +188,7 @@ p.mini { color: #999; } -img.help-tooltip { +.help-tooltip { cursor: help; } diff --git a/django/contrib/admin/static/admin/css/widgets.css b/django/contrib/admin/static/admin/css/widgets.css index 1a7ccc1e25..4f5818e340 100644 --- a/django/contrib/admin/static/admin/css/widgets.css +++ b/django/contrib/admin/static/admin/css/widgets.css @@ -202,6 +202,21 @@ a.active.selector-clearall { cursor: pointer; } +.selector .help-icon { + background: url(../img/icon-unknown.gif) no-repeat; + display: inline-block; + height: 10px; + width: 10px; + vertical-align: middle; +} + +.selector .search-label-icon { + background: url(../img/selector-search.gif) 0 2px no-repeat; + display: inline-block; + height: 18px; + width: 18px; +} + /* DATE AND TIME */ p.datetime { @@ -226,6 +241,22 @@ table p.datetime { padding-left: 0; } +.datetimeshortcuts .clock-icon, .datetimeshortcuts .date-icon { + background: none no-repeat; + display: inline-block; + height: 16px; + width: 16px; + vertical-align: middle; +} + +.datetimeshortcuts .clock-icon { + background-image: url(../img/icon_clock.gif); +} + +.datetimeshortcuts .date-icon { + background-image: url(../img/icon_calendar.gif); +} + /* URL */ p.url { diff --git a/django/contrib/admin/static/admin/js/SelectFilter2.js b/django/contrib/admin/static/admin/js/SelectFilter2.js index 62d9b8f24e..8f417dd9df 100644 --- a/django/contrib/admin/static/admin/js/SelectFilter2.js +++ b/django/contrib/admin/static/admin/js/SelectFilter2.js @@ -13,7 +13,7 @@ function findForm(node) { } window.SelectFilter = { - init: function(field_id, field_name, is_stacked, admin_static_prefix) { + init: function(field_id, field_name, is_stacked) { if (field_id.match(/__prefix__/)){ // Don't initialize on empty forms. return; @@ -43,14 +43,29 @@ window.SelectFilter = { var selector_available = quickElement('div', selector_div); selector_available.className = 'selector-available'; var title_available = quickElement('h2', selector_available, interpolate(gettext('Available %s') + ' ', [field_name])); - quickElement('img', title_available, '', 'src', admin_static_prefix + 'img/icon-unknown.gif', 'width', '10', 'height', '10', 'class', 'help help-tooltip', 'title', interpolate(gettext('This is the list of available %s. You may choose some by selecting them in the box below and then clicking the "Choose" arrow between the two boxes.'), [field_name])); + quickElement( + 'span', title_available, '', + 'class', 'help help-tooltip help-icon', + 'title', interpolate( + gettext( + 'This is the list of available %s. You may choose some by ' + + 'selecting them in the box below and then clicking the ' + + '"Choose" arrow between the two boxes.' + ), + [field_name] + ) + ); var filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter'); filter_p.className = 'selector-filter'; var search_filter_label = quickElement('label', filter_p, '', 'for', field_id + "_input"); - var search_selector_img = quickElement('img', search_filter_label, '', 'src', admin_static_prefix + 'img/selector-search.gif', 'class', 'help-tooltip', 'alt', '', 'title', interpolate(gettext("Type into this box to filter down the list of available %s."), [field_name])); + var search_selector_img = quickElement( + 'span', search_filter_label, '', + 'class', 'help-tooltip search-label-icon', + 'title', interpolate(gettext("Type into this box to filter down the list of available %s."), [field_name]) + ); filter_p.appendChild(document.createTextNode(' ')); @@ -73,7 +88,18 @@ window.SelectFilter = { var selector_chosen = quickElement('div', selector_div); selector_chosen.className = 'selector-chosen'; var title_chosen = quickElement('h2', selector_chosen, interpolate(gettext('Chosen %s') + ' ', [field_name])); - quickElement('img', title_chosen, '', 'src', admin_static_prefix + 'img/icon-unknown.gif', 'width', '10', 'height', '10', 'class', 'help help-tooltip', 'title', interpolate(gettext('This is the list of chosen %s. You may remove some by selecting them in the box below and then clicking the "Remove" arrow between the two boxes.'), [field_name])); + quickElement( + 'span', title_chosen, '', + 'class', 'help help-tooltip help-icon', + 'title', interpolate( + gettext( + 'This is the list of chosen %s. You may remove some by ' + + 'selecting them in the box below and then clicking the ' + + '"Remove" arrow between the two boxes.' + ), + [field_name] + ) + ); var to_box = quickElement('select', selector_chosen, '', 'id', field_id + '_to', 'multiple', 'multiple', 'size', from_box.size, 'name', from_box.getAttribute('name')); to_box.className = 'filtered'; diff --git a/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js b/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js index faec5a49af..7026beac75 100644 --- a/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js +++ b/django/contrib/admin/static/admin/js/admin/DateTimeShortcuts.js @@ -16,18 +16,7 @@ var DateTimeShortcuts = { shortCutsClass: 'datetimeshortcuts', // class of the clock and cal shortcuts timezoneWarningClass: 'timezonewarning', // class of the warning for timezone mismatch timezoneOffset: 0, - admin_media_prefix: '', init: function() { - // Get admin_media_prefix by grabbing it off the window object. It's - // set in the admin/base.html template, so if it's not there, someone's - // overridden the template. In that case, we'll set a clearly-invalid - // value in the hopes that someone will examine HTTP requests and see it. - if (window.__admin_media_prefix__ != undefined) { - DateTimeShortcuts.admin_media_prefix = window.__admin_media_prefix__; - } else { - DateTimeShortcuts.admin_media_prefix = '/missing-admin-media-prefix/'; - } - if (window.__admin_utc_offset__ != undefined) { var serverOffset = window.__admin_utc_offset__; var localOffset = new Date().getTimezoneOffset() * -60; @@ -115,7 +104,11 @@ var DateTimeShortcuts = { var clock_link = document.createElement('a'); clock_link.setAttribute('href', 'javascript:DateTimeShortcuts.openClock(' + num + ');'); clock_link.id = DateTimeShortcuts.clockLinkName + num; - quickElement('img', clock_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/icon_clock.gif', 'alt', gettext('Clock')); + quickElement( + 'span', clock_link, '', + 'class', 'clock-icon', + 'title', gettext('Choose a Time') + ); shortcuts_span.appendChild(document.createTextNode('\240')); shortcuts_span.appendChild(now_link); shortcuts_span.appendChild(document.createTextNode('\240|\240')); @@ -217,7 +210,11 @@ var DateTimeShortcuts = { var cal_link = document.createElement('a'); cal_link.setAttribute('href', 'javascript:DateTimeShortcuts.openCalendar(' + num + ');'); cal_link.id = DateTimeShortcuts.calendarLinkName + num; - quickElement('img', cal_link, '', 'src', DateTimeShortcuts.admin_media_prefix + 'img/icon_calendar.gif', 'alt', gettext('Calendar')); + quickElement( + 'span', cal_link, '', + 'class', 'date-icon', + 'title', gettext('Choose a Date') + ); shortcuts_span.appendChild(document.createTextNode('\240')); shortcuts_span.appendChild(today_link); shortcuts_span.appendChild(document.createTextNode('\240|\240')); diff --git a/django/contrib/admin/static/admin/js/inlines.js b/django/contrib/admin/static/admin/js/inlines.js index 0bfcd34124..6f127365e6 100644 --- a/django/contrib/admin/static/admin/js/inlines.js +++ b/django/contrib/admin/static/admin/js/inlines.js @@ -161,11 +161,11 @@ if (typeof SelectFilter != 'undefined'){ $('.selectfilter').each(function(index, value){ var namearr = value.name.split('-'); - SelectFilter.init(value.id, namearr[namearr.length-1], false, options.adminStaticPrefix ); + SelectFilter.init(value.id, namearr[namearr.length-1], false); }); $('.selectfilterstacked').each(function(index, value){ var namearr = value.name.split('-'); - SelectFilter.init(value.id, namearr[namearr.length-1], true, options.adminStaticPrefix ); + SelectFilter.init(value.id, namearr[namearr.length-1], true); }); } }; @@ -227,11 +227,11 @@ if (typeof SelectFilter != "undefined"){ $(".selectfilter").each(function(index, value){ var namearr = value.name.split('-'); - SelectFilter.init(value.id, namearr[namearr.length-1], false, options.adminStaticPrefix); + SelectFilter.init(value.id, namearr[namearr.length-1], false); }); $(".selectfilterstacked").each(function(index, value){ var namearr = value.name.split('-'); - SelectFilter.init(value.id, namearr[namearr.length-1], true, options.adminStaticPrefix); + SelectFilter.init(value.id, namearr[namearr.length-1], true); }); } }; diff --git a/django/contrib/admin/static/admin/js/inlines.min.js b/django/contrib/admin/static/admin/js/inlines.min.js index cc888a5628..aa698cf4e1 100644 --- a/django/contrib/admin/static/admin/js/inlines.min.js +++ b/django/contrib/admin/static/admin/js/inlines.min.js @@ -1,9 +1,9 @@ -(function(a){a.fn.formset=function(g){var b=a.extend({},a.fn.formset.defaults,g),i=a(this);g=i.parent();var m=function(e,k,h){var j=RegExp("("+k+"-(\\d+|__prefix__))");k=k+"-"+h;a(e).prop("for")&&a(e).prop("for",a(e).prop("for").replace(j,k));if(e.id)e.id=e.id.replace(j,k);if(e.name)e.name=e.name.replace(j,k)},l=a("#id_"+b.prefix+"-TOTAL_FORMS").prop("autocomplete","off"),d=parseInt(l.val(),10),c=a("#id_"+b.prefix+"-MAX_NUM_FORMS").prop("autocomplete","off");l=c.val()===""||c.val()-l.val()>0;i.each(function(){a(this).not("."+ -b.emptyCssClass).addClass(b.formCssClass)});if(i.length&&l){var f;if(i.prop("tagName")=="TR"){i=this.eq(-1).children().length;g.append(''+b.addText+"");f=g.find("tr:last a")}else{i.filter(":last").after('
'+b.addText+"
");f=i.filter(":last").next().find("a")}f.click(function(e){e.preventDefault();var k=a("#id_"+b.prefix+"-TOTAL_FORMS");e=a("#"+ -b.prefix+"-empty");var h=e.clone(true);h.removeClass(b.emptyCssClass).addClass(b.formCssClass).attr("id",b.prefix+"-"+d);if(h.is("tr"))h.children(":last").append('
'+b.deleteText+"
");else h.is("ul")||h.is("ol")?h.append('
  • '+b.deleteText+"
  • "):h.children(":first").append(''+b.deleteText+""); -h.find("*").each(function(){m(this,b.prefix,k.val())});h.insertBefore(a(e));a(k).val(parseInt(k.val(),10)+1);d+=1;c.val()!==""&&c.val()-k.val()<=0&&f.parent().hide();h.find("a."+b.deleteCssClass).click(function(j){j.preventDefault();j=a(this).parents("."+b.formCssClass);j.remove();d-=1;b.removed&&b.removed(j);j=a("."+b.formCssClass);a("#id_"+b.prefix+"-TOTAL_FORMS").val(j.length);if(c.val()===""||c.val()-j.length>0)f.parent().show();for(var n=0,o=j.length;n'+a.addText+""),h=b.find("tr:last a")):(d.filter(":last").after('
    '+a.addText+"
    "),h=d.filter(":last").next().find("a"));h.click(function(b){b.preventDefault();var d=c("#id_"+a.prefix+ +"-TOTAL_FORMS");b=c("#"+a.prefix+"-empty");var g=b.clone(!0);g.removeClass(a.emptyCssClass).addClass(a.formCssClass).attr("id",a.prefix+"-"+l);g.is("tr")?g.children(":last").append('
    '+a.deleteText+"
    "):g.is("ul")||g.is("ol")?g.append('
  • '+a.deleteText+"
  • "):g.children(":first").append(''+a.deleteText+ +"");g.find("*").each(function(){k(this,a.prefix,d.val())});g.insertBefore(c(b));c(d).val(parseInt(d.val(),10)+1);l+=1;""!==f.val()&&0>=f.val()-d.val()&&h.parent().hide();g.find("a."+a.deleteCssClass).click(function(b){b.preventDefault();b=c(this).parents("."+a.formCssClass);b.remove();--l;a.removed&&a.removed(b);b=c("."+a.formCssClass);c("#id_"+a.prefix+"-TOTAL_FORMS").val(b.length);(""===f.val()||0 {% block extrastyle %}{% endblock %} {% if LANGUAGE_BIDI %}{% endif %} - {% block extrahead %}{% endblock %} {% block blockbots %}{% endblock %} diff --git a/django/contrib/admin/templates/admin/edit_inline/stacked.html b/django/contrib/admin/templates/admin/edit_inline/stacked.html index 9d58146588..5b5c22d34e 100644 --- a/django/contrib/admin/templates/admin/edit_inline/stacked.html +++ b/django/contrib/admin/templates/admin/edit_inline/stacked.html @@ -23,7 +23,6 @@ (function($) { $("#{{ inline_admin_formset.formset.prefix }}-group .inline-related").stackedFormset({ prefix: '{{ inline_admin_formset.formset.prefix }}', - adminStaticPrefix: '{% static "admin/" %}', deleteText: "{% trans "Remove" %}", addText: "{% blocktrans with verbose_name=inline_admin_formset.opts.verbose_name|capfirst %}Add another {{ verbose_name }}{% endblocktrans %}" }); diff --git a/django/contrib/admin/templates/admin/edit_inline/tabular.html b/django/contrib/admin/templates/admin/edit_inline/tabular.html index c1a07cf76f..379595a044 100644 --- a/django/contrib/admin/templates/admin/edit_inline/tabular.html +++ b/django/contrib/admin/templates/admin/edit_inline/tabular.html @@ -76,7 +76,6 @@ (function($) { $("#{{ inline_admin_formset.formset.prefix }}-group .tabular.inline-related tbody tr").tabularFormset({ prefix: "{{ inline_admin_formset.formset.prefix }}", - adminStaticPrefix: '{% static "admin/" %}', addText: "{% blocktrans with inline_admin_formset.opts.verbose_name|capfirst as verbose_name %}Add another {{ verbose_name }}{% endblocktrans %}", deleteText: "{% trans 'Remove' %}" }); diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 19b4187b52..2e88e930bd 100644 --- a/django/contrib/admin/widgets.py +++ b/django/contrib/admin/widgets.py @@ -49,8 +49,8 @@ class FilteredSelectMultiple(forms.SelectMultiple): output.append('\n' - % (name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), static('admin/'))) + output.append('SelectFilter.init("id_%s", "%s", %s); });\n' + % (name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked))) return mark_safe(''.join(output)) diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt index cc2273bd56..792fdced22 100644 --- a/docs/releases/1.9.txt +++ b/docs/releases/1.9.txt @@ -252,6 +252,11 @@ Miscellaneous * ``ValuesQuerySet`` and ``ValuesListQuerySet`` have been removed. +* The ``admin/base.html`` template no longer sets + ``window.__admin_media_prefix__``. Image references in JavaScript that used + that value to construct absolute URLs have been moved to CSS for easier + customization. + .. _deprecated-features-1.9: Features deprecated in 1.9 diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py index 39f1292e67..653f845b6e 100644 --- a/tests/admin_widgets/tests.py +++ b/tests/admin_widgets/tests.py @@ -28,10 +28,6 @@ try: except ImportError: pytz = None -admin_static_prefix = lambda: { - 'ADMIN_STATIC_PREFIX': "%sadmin/" % settings.STATIC_URL, -} - class TestDataMixin(object): @@ -261,14 +257,14 @@ class FilteredSelectMultipleWidgetTest(DjangoTestCase): w = widgets.FilteredSelectMultiple('test', False) self.assertHTMLEqual( w.render('test', 'test'), - '\n' % admin_static_prefix() + '\n' ) def test_stacked_render(self): w = widgets.FilteredSelectMultiple('test', True) self.assertHTMLEqual( w.render('test', 'test'), - '\n' % admin_static_prefix() + '\n' )