Code

Ticket #7028: patch7028-1.4.rev16590.patch

File patch7028-1.4.rev16590.patch, 14.6 KB (added by Stanislas Guerra <stan__at__slashdev.me>, 3 years ago)

Patch against 1.4 Alpha

  • django/contrib/admin/options.py

     
    55    inlineformset_factory, BaseInlineFormSet) 
    66from django.contrib.contenttypes.models import ContentType 
    77from django.contrib.admin import widgets, helpers 
    8 from 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 
    99from django.contrib import messages 
    1010from django.views.decorators.csrf import csrf_protect 
    1111from django.core.exceptions import PermissionDenied, ValidationError 
     
    796796                return HttpResponseRedirect(request.path + "?_popup=1") 
    797797            else: 
    798798                return HttpResponseRedirect(request.path) 
     799        elif "_popup" in request.POST: 
     800            # object changed via raw id link popup 
     801            obj_id = repr(force_unicode(obj._get_pk_val()))[1:] 
     802            obj_url = get_related_url(obj, obj.pk) 
     803            label = obj_label(obj).replace("&#39;", r"\'") 
     804            return HttpResponse('<script type="text/javascript">opener.dismissRelatedLookupPopup(' 
     805            "window, %s, '%s', '%s');</script>" % (obj_id, obj_url, label)) 
    799806        elif "_saveasnew" in request.POST: 
    800807            msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(verbose_name), 'obj': obj} 
    801808            self.message_user(request, msg) 
  • django/contrib/admin/static/admin/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  
     
    2736    return text; 
    2837} 
    2938 
     39function getAdminMediaPrefix() { 
     40    // Copy-paste from DateTimeShortcuts.js. 
     41        if (window.__admin_media_prefix__ != undefined) { 
     42        return window.__admin_media_prefix__; 
     43    } else { 
     44        return '/missing-admin-media-prefix/'; 
     45    } 
     46} 
     47 
     48var CLEAR_RAW_ID = '<a href="#" onclick="return clearRawId(this);">' + 
     49'<img src="' + getAdminMediaPrefix() + 'img/icon_deletelink.gif" ' + 
     50'width="10" height="10" alt="Clear" title="Clear" /></a>'; 
     51 
     52// FIXME: the following produce 'gettext is not defined' errors in FireBug. 
     53// Needs to be tracked down. 
     54// (jsi18n is generally included before this in admin templates) 
     55// 
     56// 'width="10" height="10" alt="' + gettext('Clear') + '" title="' + 
     57// gettext('Clear') + '" /></a>'; 
     58 
     59function showRelatedObjectPopup(triggeringLink) { 
     60    var name = triggeringLink.parentNode.id.replace(/^view_lookup_/, ''); 
     61    name = id_to_windowname(name); 
     62    return openPopupWindow(triggeringLink.href, '_popup', name); 
     63} 
     64 
    3065function showRelatedObjectLookupPopup(triggeringLink) { 
    3166    var name = triggeringLink.id.replace(/^lookup_/, ''); 
    3267    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; 
     68    return openPopupWindow(triggeringLink.href, 'pop', name); 
    4269} 
    4370 
    44 function dismissRelatedLookupPopup(win, chosenId) { 
     71function dismissRelatedLookupPopup(win, chosenId, chosenIdHref, chosenName) { 
    4572    var name = windowname_to_id(win.name); 
    4673    var elem = document.getElementById(name); 
     74    var nameElem = document.getElementById("view_lookup_" + name); 
    4775    if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) { 
    4876        elem.value += ',' + chosenId; 
    4977    } else { 
    5078        document.getElementById(name).value = chosenId; 
    5179    } 
     80    if (nameElem) { 
     81      nameElem.innerHTML = '<a href="' + chosenIdHref + '" ' + 
     82       'onclick="return showRelatedObjectPopup(this);">' + 
     83        html_escape(chosenName) + '</a> ' + CLEAR_RAW_ID; 
     84    } 
    5285    win.close(); 
    5386} 
    5487 
    5588function showAddAnotherPopup(triggeringLink) { 
    5689    var name = triggeringLink.id.replace(/^add_/, ''); 
    5790    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; 
     91    return openPopupWindow(triggeringLink.href, '_popup', name); 
    6792} 
    6893 
    6994function dismissAddAnotherPopup(win, newId, newRepr) { 
    7095    // newId and newRepr are expected to have previously been escaped by 
    7196    // django.utils.html.escape. 
    7297    newId = html_unescape(newId); 
     98    var newRepr_escaped = newRepr; 
    7399    newRepr = html_unescape(newRepr); 
    74100    var name = windowname_to_id(win.name); 
    75101    var elem = document.getElementById(name); 
     
    84110            } else { 
    85111                elem.value = newId; 
    86112            } 
     113            var nameElem = document.getElementById("view_lookup_" + name); 
     114            if (nameElem) { 
     115                var chosenIdHref = win.location.href.replace(/\/add\/[^\/]*$/, 
     116                    '/' + newId + '/'); 
     117                nameElem.innerHTML = '<a href="' + chosenIdHref + '" ' + 
     118                  'onclick="return showRelatedObjectPopup(this);">' + 
     119                  newRepr_escaped + '</a> ' + CLEAR_RAW_ID; 
     120            } 
    87121        } 
    88122    } else { 
    89123        var toId = name + "_to"; 
     
    94128    } 
    95129    win.close(); 
    96130} 
     131 
     132function clearRawId(triggeringLink) { 
     133    triggeringLink.parentNode.previousSibling.previousSibling.previousSibling.previousSibling.value = ''; 
     134    triggeringLink.parentNode.innerHTML = ''; 
     135    return false; 
     136} 
     137 
     138function openPopupWindow(href, popup_var, name) { 
     139    if (href.indexOf('?') == -1) { 
     140        href += '?'; 
     141    } else { 
     142        href  += '&'; 
     143    } 
     144    href += popup_var + '=1'; 
     145    var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); 
     146    win.focus(); 
     147    return false; 
     148} 
  • django/contrib/admin/templatetags/admin_list.py

     
    33from django.contrib.admin.util import lookup_field, display_for_field, label_for_field 
    44from django.contrib.admin.views.main import (ALL_VAR, EMPTY_CHANGELIST_VALUE, 
    55    ORDER_VAR, PAGE_VAR, SEARCH_VAR) 
     6from django.contrib.admin.util import obj_label, get_related_url 
    67from django.core.exceptions import ObjectDoesNotExist 
    78from django.db import models 
    89from django.templatetags.static import static 
     
    214215                attr = pk 
    215216            value = result.serializable_value(attr) 
    216217            result_id = repr(force_unicode(value))[1:] 
    217             yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \ 
    218                 (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)) 
     218            result_name = obj_label(result) 
     219            result_url = get_related_url(result, result.pk) 
     220            yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % 
     221                (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)) 
    219222        else: 
    220223            # By default the fields come from ModelAdmin.list_editable, but if we pull 
    221224            # the fields out of the form instead of list_editable custom admins 
  • django/contrib/admin/widgets.py

     
    1313from django.utils.translation import ugettext as _ 
    1414from django.utils.safestring import mark_safe 
    1515from django.utils.encoding import force_unicode 
     16from django.contrib.admin.util import get_related_url, obj_label 
    1617 
    1718class FilteredSelectMultiple(forms.SelectMultiple): 
    1819    """ 
     
    124125            attrs = {} 
    125126        extra = [] 
    126127        if rel_to in self.admin_site._registry: 
    127             # The related object is registered with the same AdminSite 
    128             related_url = reverse('admin:%s_%s_changelist' % 
    129                                     (rel_to._meta.app_label, 
    130                                     rel_to._meta.module_name), 
    131                                     current_app=self.admin_site.name) 
    132  
     128            related_url = get_related_url(self.rel.to) 
    133129            params = self.url_parameters() 
    134130            if params: 
    135131                url = u'?' + u'&amp;'.join([u'%s=%s' % (k, v) for k, v in params.items()]) 
     
    139135                attrs['class'] = 'vForeignKeyRawIdAdminField' # The JavaScript code looks for this hook. 
    140136            # TODO: "lookup_id_" is hard-coded here. This should instead use 
    141137            # the correct API to determine the ID dynamically. 
    142             extra.append(u'<a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' 
     138            extra.append(u' <a href="%s%s" class="related-lookup" id="lookup_id_%s" onclick="return showRelatedObjectLookupPopup(this);"> ' 
    143139                            % (related_url, url, name)) 
    144140            extra.append(u'<img src="%s" width="16" height="16" alt="%s" /></a>' 
    145141                            % (static('admin/img/selector-search.gif'), _('Lookup'))) 
    146142        output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)] + extra 
    147         if value: 
    148             output.append(self.label_for_value(value)) 
     143        output.append(self.label_for_value(value, 'view_lookup_id_%s' % name)) 
    149144        return mark_safe(u''.join(output)) 
    150145 
    151146    def base_url_parameters(self): 
     
    157152        params.update({TO_FIELD_VAR: self.rel.get_related_field().name}) 
    158153        return params 
    159154 
    160     def label_for_value(self, value): 
    161         key = self.rel.get_related_field().name 
    162         try: 
    163             obj = self.rel.to._default_manager.using(self.db).get(**{key: value}) 
    164             return '&nbsp;<strong>%s</strong>' % escape(Truncator(obj).words(14, truncate='...')) 
    165         except (ValueError, self.rel.to.DoesNotExist): 
    166             return '' 
     155    def label_for_value(self, value, name): 
     156        if value: 
     157            key = self.rel.get_related_field().name 
     158            obj = self.rel.to._default_manager.using( 
     159                    self.db).get(**{key: value}) 
     160            related_url = get_related_url(obj, obj.pk) 
     161            return (' <strong id="%(name)s"><a href="%(url)s" ' 
     162                    'onclick="return showRelatedObjectPopup(this);">%(label)s</a> ' 
     163                    '<a href="#" onclick="return clearRawId(this);">' 
     164                    '<img src="%(img_src)s" ' 
     165                    'width="10" height="10" alt="%(clear)s" title="%(clear)s" />' 
     166                    '</a></strong>' % {'name': name, 'url': related_url, 
     167                        'label': obj_label(obj), 
     168                        'img_src': static('admin/img/icon_deletelink.gif'), 
     169                        'clear': _("Clear"),} 
     170                    ) 
     171        else: 
     172            # a placeholder that will be filled in 
     173            # JavaScript dismissRelatedLookupPopup() 
     174            return ' <strong id="%s"></strong>' % name 
    167175 
     176 
    168177class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 
    169178    """ 
    170179    A Widget for displaying ManyToMany ids in the "raw_id" interface rather than 
     
    185194    def url_parameters(self): 
    186195        return self.base_url_parameters() 
    187196 
    188     def label_for_value(self, value): 
     197    def label_for_value(self, value, name): 
    189198        return '' 
    190199 
    191200    def value_from_datadict(self, data, files, name): 
     
    238247 
    239248    def render(self, name, value, *args, **kwargs): 
    240249        rel_to = self.rel.to 
    241         info = (rel_to._meta.app_label, rel_to._meta.object_name.lower()) 
    242250        self.widget.choices = self.choices 
    243251        output = [self.widget.render(name, value, *args, **kwargs)] 
    244252        if self.can_add_related: 
    245             related_url = reverse('admin:%s_%s_add' % info, current_app=self.admin_site.name) 
     253            related_url = get_related_url(rel_to, 'add', self.admin_site) 
    246254            # TODO: "add_id_" is hard-coded here. This should instead use the 
    247255            # correct API to determine the ID dynamically. 
    248256            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 
     
    302302    else: 
    303303        return smart_unicode(value) 
    304304 
     305def get_related_url(rel_to, action=None, admin_site=None): 
     306    reverse_path = 'admin:%s_%s' 
     307    rel_path = '%s%s/%s/' 
     308    params = [rel_to._meta.app_label, rel_to._meta.object_name.lower()] 
    305309 
     310    if action: 
     311        reverse_path += '_%s' 
     312        rel_path += '%s/' 
     313        params.append(action) 
     314 
     315    if admin_site: 
     316        try: 
     317            return reverse(reverse_path % tuple(params), 
     318                    current_app=admin_site.name) 
     319        except NoReverseMatch: 
     320            params.insert(0, admin_site.root_path) 
     321            return rel_path % tuple(params) 
     322 
     323    params.insert(0, '../../../') 
     324    return rel_path % tuple(params) 
     325 
     326def obj_label(obj): 
     327    return escape(truncate_words(obj, 7)) 
     328 
     329 
    306330class NotRelationField(Exception): 
    307331    pass 
    308332