Ticket #7028: patch7028-1.3.patch

File patch7028-1.3.patch, 15.0 KB (added by stan <stan__at__slashdev.me>, 4 years ago)

Previous patch adapted to 1.3

  • django/contrib/admin/media/js/admin/RelatedObjectLookups.js

     
    1111    return text;
    1212}
    1313
     14function html_escape(text) {
     15    text = text.replace(/&/g, '&amp;');
     16    text = text.replace(/</g, '&lt;');
     17    text = text.replace(/>/g, '&gt;');
     18    text = text.replace(/"/g, '&quot;');
     19    text = text.replace(/'/g, '&#39;');
     20    return text;
     21}
     22
    1423// IE doesn't accept periods or dashes in the window name, but the element IDs
    1524// we use to generate popup window names may contain them, therefore we map them
    1625// to allowed characters in a reversible way so that we can locate the correct
     
    2635    text = text.replace(/__dash__/g, '-');
    2736    return text;
    2837}
     38function getAdminMediaPrefix() {
     39    // Deduce admin_media_prefix by looking at the <script>s in the
     40    // current document and finding the URL of *this* module.
     41    // Copy-paste from DateTimeShortcuts.js, makes sense as a
     42    // separate function in core.js.
     43    var scripts = document.getElementsByTagName('script');
    2944
     45    for (var i=0; i < scripts.length; i++) {
     46        if (scripts[i].src.match(/RelatedObjectLookups/)) {
     47            var idx = scripts[i].src.indexOf('js/admin/RelatedObjectLookups');
     48            return scripts[i].src.substring(0, idx);
     49        }
     50    }
     51    // poor man's assert
     52    alert('This line is unreachable. Please file a bug if you see this message.');
     53}
     54
     55var CLEAR_RAW_ID = '<a href="#" onclick="return clearRawId(this);">' +
     56'<img src="' + getAdminMediaPrefix() + 'img/admin/icon_deletelink.gif" ' +
     57'width="10" height="10" alt="Clear" title="Clear" /></a>';
     58
     59// FIXME: the following produce 'gettext is not defined' errors in FireBug.
     60// Needs to be tracked down.
     61// (jsi18n is generally included before this in admin templates)
     62//
     63// 'width="10" height="10" alt="' + gettext('Clear') + '" title="' +
     64// gettext('Clear') + '" /></a>';
     65
     66function showRelatedObjectPopup(triggeringLink) {
     67    var name = triggeringLink.parentNode.id.replace(/^view_lookup_/, '');
     68    name = id_to_windowname(name);
     69    return openPopupWindow(triggeringLink.href, '_popup', name);
     70}
     71
    3072function showRelatedObjectLookupPopup(triggeringLink) {
    3173    var name = triggeringLink.id.replace(/^lookup_/, '');
    3274    name = id_to_windowname(name);
    33     var href;
    34     if (triggeringLink.href.search(/\?/) >= 0) {
    35         href = triggeringLink.href + '&pop=1';
    36     } else {
    37         href = triggeringLink.href + '?pop=1';
    38     }
    39     var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
    40     win.focus();
    41     return false;
     75    return openPopupWindow(triggeringLink.href, 'pop', name);
    4276}
    4377
    44 function dismissRelatedLookupPopup(win, chosenId) {
     78function dismissRelatedLookupPopup(win, chosenId, chosenIdHref, chosenName) {
    4579    var name = windowname_to_id(win.name);
    4680    var elem = document.getElementById(name);
     81    var nameElem = document.getElementById("view_lookup_" + name);
    4782    if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) {
    4883        elem.value += ',' + chosenId;
    4984    } else {
    5085        document.getElementById(name).value = chosenId;
    5186    }
     87    if (nameElem) {
     88      nameElem.innerHTML = '<a href="' + chosenIdHref + '" ' +
     89       'onclick="return showRelatedObjectPopup(this);">' +
     90        html_escape(chosenName) + '</a> ' + CLEAR_RAW_ID;
     91    }
    5292    win.close();
    5393}
    5494
    5595function showAddAnotherPopup(triggeringLink) {
    5696    var name = triggeringLink.id.replace(/^add_/, '');
    5797    name = id_to_windowname(name);
    58     href = triggeringLink.href
    59     if (href.indexOf('?') == -1) {
    60         href += '?_popup=1';
    61     } else {
    62         href  += '&_popup=1';
    63     }
    64     var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
    65     win.focus();
    66     return false;
     98    return openPopupWindow(triggeringLink.href, '_popup', name);
    6799}
    68100
    69101function dismissAddAnotherPopup(win, newId, newRepr) {
    70102    // newId and newRepr are expected to have previously been escaped by
    71103    // django.utils.html.escape.
    72104    newId = html_unescape(newId);
     105    var newRepr_escaped = newRepr;
    73106    newRepr = html_unescape(newRepr);
    74107    var name = windowname_to_id(win.name);
    75108    var elem = document.getElementById(name);
     
    84117            } else {
    85118                elem.value = newId;
    86119            }
     120            var nameElem = document.getElementById("view_lookup_" + name);
     121            if (nameElem) {
     122                var chosenIdHref = win.location.href.replace(/\/add\/[^\/]*$/,
     123                    '/' + newId + '/');
     124                nameElem.innerHTML = '<a href="' + chosenIdHref + '" ' +
     125                  'onclick="return showRelatedObjectPopup(this);">' +
     126                  newRepr_escaped + '</a> ' + CLEAR_RAW_ID;
     127            }
    87128        }
    88129    } else {
    89130        var toId = name + "_to";
     
    94135    }
    95136    win.close();
    96137}
     138
     139function clearRawId(triggeringLink) {
     140    triggeringLink.parentNode.previousSibling.previousSibling.previousSibling.previousSibling.value = '';
     141    triggeringLink.parentNode.innerHTML = '';
     142    return false;
     143}
     144
     145function openPopupWindow(href, popup_var, name) {
     146    if (href.indexOf('?') == -1) {
     147        href += '?';
     148    } else {
     149        href  += '&';
     150    }
     151    href += popup_var + '=1';
     152    var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes');
     153    win.focus();
     154    return false;
     155}
  • django/contrib/admin/options.py

     
    55from django.contrib.contenttypes.models import ContentType
    66from django.contrib.admin import widgets, helpers
    77from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict
     8from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict, obj_label, get_related_url
    89from django.contrib import messages
    910from django.views.decorators.csrf import csrf_protect
    1011from django.core.exceptions import PermissionDenied, ValidationError
     
    763764                return HttpResponseRedirect(request.path + "?_popup=1")
    764765            else:
    765766                return HttpResponseRedirect(request.path)
     767        elif "_popup" in request.POST:
     768            # object changed via raw id link popup
     769            obj_id = repr(force_unicode(obj._get_pk_val()))[1:]
     770            obj_url = get_related_url(obj, obj.pk)
     771            label = obj_label(obj).replace("&#39;", r"\'")
     772            return HttpResponse('<script type="text/javascript">opener.dismissRelatedLookupPopup('
     773            "window, %s, '%s', '%s');</script>" % (obj_id, obj_url, label))
    766774        elif "_saveasnew" in request.POST:
    767775            msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(verbose_name), 'obj': obj}
    768776            self.message_user(request, msg)
  • django/contrib/admin/templatetags/admin_list.py

     
    44from django.contrib.admin.util import lookup_field, display_for_field, label_for_field
    55from django.contrib.admin.views.main import (ALL_VAR, EMPTY_CHANGELIST_VALUE,
    66    ORDER_VAR, ORDER_TYPE_VAR, PAGE_VAR, SEARCH_VAR)
     7from django.contrib.admin.util import obj_label, get_related_url
    78from django.core.exceptions import ObjectDoesNotExist
    89from django.db import models
    910from django.utils import formats
     
    182183                attr = pk
    183184            value = result.serializable_value(attr)
    184185            result_id = repr(force_unicode(value))[1:]
    185             yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \
    186                 (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(window, %s); return false;"' % result_id or ''), conditional_escape(result_repr), table_tag))
     186            result_name = obj_label(result)
     187            result_url = get_related_url(result, result.pk)
     188            yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' %
     189                (table_tag, row_class, url, (cl.is_popup and ' onclick="opener.dismissRelatedLookupPopup(' "window, %s, '%s', '%s'); return false;\"" % (result_id, result_url, result_name.replace("&#39;", r"\'")) or ''), conditional_escape(result_repr), table_tag))
    187190        else:
    188191            # By default the fields come from ModelAdmin.list_editable, but if we pull
    189192            # the fields out of the form instead of list_editable custom admins
  • django/contrib/admin/widgets.py

     
    1414from django.utils.encoding import force_unicode
    1515from django.conf import settings
    1616from django.core.urlresolvers import reverse, NoReverseMatch
     17from django.contrib.admin.util import get_related_url, obj_label
    1718
    1819class FilteredSelectMultiple(forms.SelectMultiple):
    1920    """
     
    124125    def render(self, name, value, attrs=None):
    125126        if attrs is None:
    126127            attrs = {}
    127         related_url = '../../../%s/%s/' % (self.rel.to._meta.app_label, self.rel.to._meta.object_name.lower())
     128        related_url = get_related_url(self.rel.to)
    128129        params = self.url_parameters()
    129130        if params:
    130131            url = u'?' + u'&amp;'.join([u'%s=%s' % (k, v) for k, v in params.items()])
     
    135136        output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)]
    136137        # TODO: "id_" is hard-coded here. This should instead use the correct
    137138        # API to determine the ID dynamically.
    138         output.append(u'<a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \
     139        output.append(u' <a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' % \
    139140            (related_url, url, name))
    140         output.append(u'<img src="%simg/admin/selector-search.gif" width="16" height="16" alt="%s" /></a>' % (settings.ADMIN_MEDIA_PREFIX, _('Lookup')))
    141         if value:
    142             output.append(self.label_for_value(value))
     141        output.append('<img src="%(prefix)simg/admin/selector-search.gif" width="16" height="16" alt="%(title)s" title="%(title)s" /></a>' % {'prefix': settings.ADMIN_MEDIA_PREFIX, 'title': _('Lookup')})
     142        output.append(self.label_for_value(value, 'view_lookup_id_%s' % name))
    143143        return mark_safe(u''.join(output))
    144144
    145145    def base_url_parameters(self):
     
    151151        params.update({TO_FIELD_VAR: self.rel.get_related_field().name})
    152152        return params
    153153
    154     def label_for_value(self, value):
    155         key = self.rel.get_related_field().name
    156         try:
    157             obj = self.rel.to._default_manager.using(self.db).get(**{key: value})
    158             return '&nbsp;<strong>%s</strong>' % escape(truncate_words(obj, 14))
    159         except (ValueError, self.rel.to.DoesNotExist):
    160             return ''
     154    def label_for_value(self, value, name):
     155        if value:
     156            key = self.rel.get_related_field().name
     157            obj = self.rel.to._default_manager.using(
     158                    self.db).get(**{key: value})
     159            related_url = get_related_url(obj, obj.pk)
     160            return (' <strong id="%(name)s"><a href="%(url)s" '
     161                    'onclick="return showRelatedObjectPopup(this);">%(label)s</a> '
     162                    '<a href="#" onclick="return clearRawId(this);">'
     163                    '<img src="%(prefix)simg/admin/icon_deletelink.gif" '
     164                    'width="10" height="10" alt="%(clear)s" title="%(clear)s" />'
     165                    '</a></strong>' % {'name': name, 'url': related_url,
     166                        'label': obj_label(obj),
     167                        'prefix': settings.ADMIN_MEDIA_PREFIX,
     168                        'clear': _("Clear"),}
     169                    )
     170        else:
     171            # a placeholder that will be filled in
     172            # JavaScript dismissRelatedLookupPopup()
     173            return ' <strong id="%s"></strong>' % name
    161174
    162175class ManyToManyRawIdWidget(ForeignKeyRawIdWidget):
    163176    """
     
    177190    def url_parameters(self):
    178191        return self.base_url_parameters()
    179192
    180     def label_for_value(self, value):
     193    def label_for_value(self, value, name):
    181194        return ''
    182195
    183196    def value_from_datadict(self, data, files, name):
     
    229242    media = property(_media)
    230243
    231244    def render(self, name, value, *args, **kwargs):
    232         rel_to = self.rel.to
    233         info = (rel_to._meta.app_label, rel_to._meta.object_name.lower())
    234         try:
    235             related_url = reverse('admin:%s_%s_add' % info, current_app=self.admin_site.name)
    236         except NoReverseMatch:
    237             info = (self.admin_site.root_path, rel_to._meta.app_label, rel_to._meta.object_name.lower())
    238             related_url = '%s%s/%s/add/' % info
    239245        self.widget.choices = self.choices
    240246        output = [self.widget.render(name, value, *args, **kwargs)]
     247        rel_to = self.rel.to
    241248        if self.can_add_related:
     249            related_url = get_related_url(rel_to, 'add', self.admin_site)
    242250            # TODO: "id_" is hard-coded here. This should instead use the correct
    243251            # API to determine the ID dynamically.
    244252            output.append(u'<a href="%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \
  • django/contrib/admin/util.py

     
    66from django.utils import formats
    77from django.utils.html import escape
    88from django.utils.safestring import mark_safe
    9 from django.utils.text import capfirst
     9from django.utils.text import capfirst, truncate_words
    1010from django.utils.encoding import force_unicode, smart_unicode, smart_str
    1111from django.utils.translation import ungettext
    1212from django.core.urlresolvers import reverse
     
    295295        return smart_unicode(value)
    296296
    297297
     298def get_related_url(rel_to, action=None, admin_site=None):
     299    reverse_path = 'admin:%s_%s'
     300    rel_path = '%s%s/%s/'
     301    params = [rel_to._meta.app_label, rel_to._meta.object_name.lower()]
     302
     303    if action:
     304        reverse_path += '_%s'
     305        rel_path += '%s/'
     306        params.append(action)
     307
     308    if admin_site:
     309        try:
     310            return reverse(reverse_path % tuple(params),
     311                    current_app=admin_site.name)
     312        except NoReverseMatch:
     313            params.insert(0, admin_site.root_path)
     314            return rel_path % tuple(params)
     315
     316    params.insert(0, '../../../')
     317    return rel_path % tuple(params)
     318
     319
     320def obj_label(obj):
     321    return escape(truncate_words(obj, 7))
     322
     323
    298324class NotRelationField(Exception):
    299325    pass
    300326
Back to Top