Ticket #7028: patch7028-1.3.patch
File patch7028-1.3.patch, 15.0 KB (added by , 14 years ago) |
---|
-
django/contrib/admin/media/js/admin/RelatedObjectLookups.js
11 11 return text; 12 12 } 13 13 14 function html_escape(text) { 15 text = text.replace(/&/g, '&'); 16 text = text.replace(/</g, '<'); 17 text = text.replace(/>/g, '>'); 18 text = text.replace(/"/g, '"'); 19 text = text.replace(/'/g, '''); 20 return text; 21 } 22 14 23 // IE doesn't accept periods or dashes in the window name, but the element IDs 15 24 // we use to generate popup window names may contain them, therefore we map them 16 25 // to allowed characters in a reversible way so that we can locate the correct … … 26 35 text = text.replace(/__dash__/g, '-'); 27 36 return text; 28 37 } 38 function 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'); 29 44 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 55 var 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 66 function 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 30 72 function showRelatedObjectLookupPopup(triggeringLink) { 31 73 var name = triggeringLink.id.replace(/^lookup_/, ''); 32 74 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); 42 76 } 43 77 44 function dismissRelatedLookupPopup(win, chosenId ) {78 function dismissRelatedLookupPopup(win, chosenId, chosenIdHref, chosenName) { 45 79 var name = windowname_to_id(win.name); 46 80 var elem = document.getElementById(name); 81 var nameElem = document.getElementById("view_lookup_" + name); 47 82 if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) { 48 83 elem.value += ',' + chosenId; 49 84 } else { 50 85 document.getElementById(name).value = chosenId; 51 86 } 87 if (nameElem) { 88 nameElem.innerHTML = '<a href="' + chosenIdHref + '" ' + 89 'onclick="return showRelatedObjectPopup(this);">' + 90 html_escape(chosenName) + '</a> ' + CLEAR_RAW_ID; 91 } 52 92 win.close(); 53 93 } 54 94 55 95 function showAddAnotherPopup(triggeringLink) { 56 96 var name = triggeringLink.id.replace(/^add_/, ''); 57 97 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); 67 99 } 68 100 69 101 function dismissAddAnotherPopup(win, newId, newRepr) { 70 102 // newId and newRepr are expected to have previously been escaped by 71 103 // django.utils.html.escape. 72 104 newId = html_unescape(newId); 105 var newRepr_escaped = newRepr; 73 106 newRepr = html_unescape(newRepr); 74 107 var name = windowname_to_id(win.name); 75 108 var elem = document.getElementById(name); … … 84 117 } else { 85 118 elem.value = newId; 86 119 } 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 } 87 128 } 88 129 } else { 89 130 var toId = name + "_to"; … … 94 135 } 95 136 win.close(); 96 137 } 138 139 function clearRawId(triggeringLink) { 140 triggeringLink.parentNode.previousSibling.previousSibling.previousSibling.previousSibling.value = ''; 141 triggeringLink.parentNode.innerHTML = ''; 142 return false; 143 } 144 145 function 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
5 5 from django.contrib.contenttypes.models import ContentType 6 6 from django.contrib.admin import widgets, helpers 7 7 from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict 8 from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict, obj_label, get_related_url 8 9 from django.contrib import messages 9 10 from django.views.decorators.csrf import csrf_protect 10 11 from django.core.exceptions import PermissionDenied, ValidationError … … 763 764 return HttpResponseRedirect(request.path + "?_popup=1") 764 765 else: 765 766 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("'", r"\'") 772 return HttpResponse('<script type="text/javascript">opener.dismissRelatedLookupPopup(' 773 "window, %s, '%s', '%s');</script>" % (obj_id, obj_url, label)) 766 774 elif "_saveasnew" in request.POST: 767 775 msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(verbose_name), 'obj': obj} 768 776 self.message_user(request, msg) -
django/contrib/admin/templatetags/admin_list.py
4 4 from django.contrib.admin.util import lookup_field, display_for_field, label_for_field 5 5 from django.contrib.admin.views.main import (ALL_VAR, EMPTY_CHANGELIST_VALUE, 6 6 ORDER_VAR, ORDER_TYPE_VAR, PAGE_VAR, SEARCH_VAR) 7 from django.contrib.admin.util import obj_label, get_related_url 7 8 from django.core.exceptions import ObjectDoesNotExist 8 9 from django.db import models 9 10 from django.utils import formats … … 182 183 attr = pk 183 184 value = result.serializable_value(attr) 184 185 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("'", r"\'")) or ''), conditional_escape(result_repr), table_tag)) 187 190 else: 188 191 # By default the fields come from ModelAdmin.list_editable, but if we pull 189 192 # the fields out of the form instead of list_editable custom admins -
django/contrib/admin/widgets.py
14 14 from django.utils.encoding import force_unicode 15 15 from django.conf import settings 16 16 from django.core.urlresolvers import reverse, NoReverseMatch 17 from django.contrib.admin.util import get_related_url, obj_label 17 18 18 19 class FilteredSelectMultiple(forms.SelectMultiple): 19 20 """ … … 124 125 def render(self, name, value, attrs=None): 125 126 if attrs is None: 126 127 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) 128 129 params = self.url_parameters() 129 130 if params: 130 131 url = u'?' + u'&'.join([u'%s=%s' % (k, v) for k, v in params.items()]) … … 135 136 output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)] 136 137 # TODO: "id_" is hard-coded here. This should instead use the correct 137 138 # 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);"> ' % \ 139 140 (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)) 143 143 return mark_safe(u''.join(output)) 144 144 145 145 def base_url_parameters(self): … … 151 151 params.update({TO_FIELD_VAR: self.rel.get_related_field().name}) 152 152 return params 153 153 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 ' <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 161 174 162 175 class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 163 176 """ … … 177 190 def url_parameters(self): 178 191 return self.base_url_parameters() 179 192 180 def label_for_value(self, value ):193 def label_for_value(self, value, name): 181 194 return '' 182 195 183 196 def value_from_datadict(self, data, files, name): … … 229 242 media = property(_media) 230 243 231 244 def render(self, name, value, *args, **kwargs): 232 rel_to = self.rel.to233 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/' % info239 245 self.widget.choices = self.choices 240 246 output = [self.widget.render(name, value, *args, **kwargs)] 247 rel_to = self.rel.to 241 248 if self.can_add_related: 249 related_url = get_related_url(rel_to, 'add', self.admin_site) 242 250 # TODO: "id_" is hard-coded here. This should instead use the correct 243 251 # API to determine the ID dynamically. 244 252 output.append(u'<a href="%s" class="add-another" id="add_id_%s" onclick="return showAddAnotherPopup(this);"> ' % \ -
django/contrib/admin/util.py
6 6 from django.utils import formats 7 7 from django.utils.html import escape 8 8 from django.utils.safestring import mark_safe 9 from django.utils.text import capfirst 9 from django.utils.text import capfirst, truncate_words 10 10 from django.utils.encoding import force_unicode, smart_unicode, smart_str 11 11 from django.utils.translation import ungettext 12 12 from django.core.urlresolvers import reverse … … 295 295 return smart_unicode(value) 296 296 297 297 298 def 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 320 def obj_label(obj): 321 return escape(truncate_words(obj, 7)) 322 323 298 324 class NotRelationField(Exception): 299 325 pass 300 326