Ticket #7028: patch7028-1.4.5.patch
File patch7028-1.4.5.patch, 23.3 KB (added by , 12 years ago) |
---|
-
django/contrib/admin/options.py
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 78a08cd..2c9df28 100644
a b from django.forms.models import (modelform_factory, modelformset_factory, 6 6 inlineformset_factory, BaseInlineFormSet) 7 7 from django.contrib.contenttypes.models import ContentType 8 8 from django.contrib.admin import widgets, helpers 9 from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict 9 from django.contrib.admin.util import unquote, flatten_fieldsets, get_deleted_objects, model_format_dict, obj_label 10 10 from django.contrib.admin.templatetags.admin_static import static 11 11 from django.contrib import messages 12 12 from django.views.decorators.csrf import csrf_protect … … class ModelAdmin(BaseModelAdmin): 826 826 return HttpResponseRedirect(request.path + "?_popup=1") 827 827 else: 828 828 return HttpResponseRedirect(request.path) 829 elif "_popup" in request.POST: 830 # object changed via raw id link popup 831 obj_id = repr(force_unicode(obj._get_pk_val()))[1:] 832 obj_url = reverse('admin:%s_%s_change' % (opts.app_label, opts.object_name.lower()), args=(obj.pk,), current_app=self.admin_site.name) 833 label = obj_label(obj).replace("'", r"\'") 834 return HttpResponse('<script type="text/javascript">opener.dismissRelatedLookupPopup(' 835 "window, %s, '%s', '%s');</script>" % (obj_id, obj_url, label)) 829 836 elif "_saveasnew" in request.POST: 830 837 msg = _('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': force_unicode(verbose_name), 'obj': obj} 831 838 self.message_user(request, msg) -
django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js
diff --git a/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js b/django/contrib/admin/static/admin/js/admin/RelatedObjectLookups.js index ce54fa5..77ea7ee 100644
a b function html_unescape(text) { 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 … … function windowname_to_id(text) { 27 36 return text; 28 37 } 29 38 39 function 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 48 var 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 59 function 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 30 65 function showRelatedObjectLookupPopup(triggeringLink) { 31 66 var name = triggeringLink.id.replace(/^lookup_/, ''); 32 67 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); 42 69 } 43 70 44 function dismissRelatedLookupPopup(win, chosenId ) {71 function dismissRelatedLookupPopup(win, chosenId, chosenIdHref, chosenName) { 45 72 var name = windowname_to_id(win.name); 46 73 var elem = document.getElementById(name); 74 var nameElem = document.getElementById("view_lookup_" + name); 47 75 if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) { 48 76 elem.value += ',' + chosenId; 49 77 } else { 50 78 document.getElementById(name).value = chosenId; 51 79 } 80 if (nameElem) { 81 nameElem.innerHTML = '<a href="' + chosenIdHref + '" ' + 82 'onclick="return showRelatedObjectPopup(this);">' + 83 html_escape(chosenName) + '</a> ' + CLEAR_RAW_ID; 84 } 52 85 win.close(); 53 86 } 54 87 55 88 function showAddAnotherPopup(triggeringLink) { 56 89 var name = triggeringLink.id.replace(/^add_/, ''); 57 90 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); 67 92 } 68 93 69 94 function dismissAddAnotherPopup(win, newId, newRepr) { 70 95 // newId and newRepr are expected to have previously been escaped by 71 96 // django.utils.html.escape. 72 97 newId = html_unescape(newId); 98 var newRepr_escaped = newRepr; 73 99 newRepr = html_unescape(newRepr); 74 100 var name = windowname_to_id(win.name); 75 101 var elem = document.getElementById(name); … … function dismissAddAnotherPopup(win, newId, newRepr) { 85 111 } else { 86 112 elem.value = newId; 87 113 } 114 var nameElem = document.getElementById("view_lookup_" + name); 115 if (nameElem) { 116 var chosenIdHref = win.location.href.replace(/\/add\/[^\/]*$/, 117 '/' + newId + '/'); 118 nameElem.innerHTML = '<a href="' + chosenIdHref + '" ' + 119 'onclick="return showRelatedObjectPopup(this);">' + 120 newRepr_escaped + '</a> ' + CLEAR_RAW_ID; 121 } 88 122 } 89 123 } else { 90 124 var toId = name + "_to"; … … function dismissAddAnotherPopup(win, newId, newRepr) { 95 129 } 96 130 win.close(); 97 131 } 132 133 function clearRawId(triggeringLink) { 134 triggeringLink.parentNode.previousSibling.previousSibling.previousSibling.previousSibling.value = ''; 135 triggeringLink.parentNode.innerHTML = ''; 136 return false; 137 } 138 139 function openPopupWindow(href, popup_var, name) { 140 if (href.indexOf('?') == -1) { 141 href += '?'; 142 } else { 143 href += '&'; 144 } 145 href += popup_var + '=1'; 146 var win = window.open(href, name, 'height=500,width=800,resizable=yes,scrollbars=yes'); 147 win.focus(); 148 return false; 149 } -
django/contrib/admin/templatetags/admin_list.py
diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index e778429..036c0e0 100644
a b import datetime 3 3 from django.contrib.admin.util import lookup_field, display_for_field, label_for_field 4 4 from django.contrib.admin.views.main import (ALL_VAR, EMPTY_CHANGELIST_VALUE, 5 5 ORDER_VAR, PAGE_VAR, SEARCH_VAR) 6 from django.contrib.admin.util import obj_label 6 7 from django.contrib.admin.templatetags.admin_static import static 7 8 from django.core.exceptions import ObjectDoesNotExist 9 from django.core.urlresolvers import reverse 8 10 from django.db import models 9 11 from django.utils import formats 10 12 from django.utils.html import escape, conditional_escape … … def items_for_result(cl, result, form): 221 223 attr = pk 222 224 value = result.serializable_value(attr) 223 225 result_id = repr(force_unicode(value))[1:] 224 yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % \ 225 (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)) 226 result_name = obj_label(result) 227 result_url = reverse('admin:%s_%s_change' % (result._meta.app_label, result._meta.object_name.lower()), 228 args=(result.pk,), 229 current_app=cl.model_admin.admin_site.name) 230 yield mark_safe(u'<%s%s><a href="%s"%s>%s</a></%s>' % 231 (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)) 226 232 else: 227 233 # By default the fields come from ModelAdmin.list_editable, but if we pull 228 234 # the fields out of the form instead of list_editable custom admins -
django/contrib/admin/util.py
diff --git a/django/contrib/admin/util.py b/django/contrib/admin/util.py index 61182a6..16b276c 100644
a b from django.forms.forms import pretty_name 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 import timezone 11 11 from django.utils.encoding import force_unicode, smart_unicode, smart_str 12 12 from django.utils.translation import ungettext … … def display_for_field(value, field): 332 332 else: 333 333 return smart_unicode(value) 334 334 335 def obj_label(obj): 336 return escape(truncate_words(obj, 7)) 337 335 338 336 339 class NotRelationField(Exception): 337 340 pass -
django/contrib/admin/widgets.py
diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 29958b2..0064ebb 100644
a b from django.core.urlresolvers import reverse 9 9 from django.forms.widgets import RadioFieldRenderer 10 10 from django.forms.util import flatatt 11 11 from django.utils.html import escape 12 from django.utils.text import Truncator 12 from django.utils.text import Truncator, truncate_words 13 13 from django.utils.translation import ugettext as _ 14 14 from django.utils.safestring import mark_safe 15 15 from django.utils.encoding import force_unicode 16 from django.contrib.admin.util import obj_label 16 17 17 18 18 19 class FilteredSelectMultiple(forms.SelectMultiple): … … class ForeignKeyRawIdWidget(forms.TextInput): 160 161 extra.append(u'<img src="%s" width="16" height="16" alt="%s" /></a>' 161 162 % (static('admin/img/selector-search.gif'), _('Lookup'))) 162 163 output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)] + extra 163 if value: 164 output.append(self.label_for_value(value)) 164 output.append(self.label_for_value(value, 'view_lookup_id_%s' % name)) 165 165 return mark_safe(u''.join(output)) 166 166 167 167 def base_url_parameters(self): … … class ForeignKeyRawIdWidget(forms.TextInput): 173 173 params.update({TO_FIELD_VAR: self.rel.get_related_field().name}) 174 174 return params 175 175 176 def label_for_value(self, value): 177 key = self.rel.get_related_field().name 178 try: 179 obj = self.rel.to._default_manager.using(self.db).get(**{key: value}) 180 return ' <strong>%s</strong>' % escape(Truncator(obj).words(14, truncate='...')) 181 except (ValueError, self.rel.to.DoesNotExist): 182 return '' 176 def label_for_value(self, value, name): 177 if value: 178 rel_to = self.rel.to 179 label, related_url = '', '' 180 key = self.rel.get_related_field().name 181 try: 182 obj = rel_to._default_manager.using( 183 self.db).get(**{key: value}) 184 except: 185 pass 186 else: 187 label = obj_label(obj) 188 if rel_to in self.admin_site._registry: 189 try: 190 related_url = reverse('admin:%s_%s_change' % 191 (obj._meta.app_label, 192 obj._meta.module_name), 193 args=(obj.pk,), 194 current_app=self.admin_site.name) 195 except NoReverseMatch: 196 raise 197 if label and related_url: 198 label = '<a href="%s" onclick="return showRelatedObjectPopup(this);">%s</a>' % (related_url, label) 199 200 return (' <strong id="%(name)s">%(label)s' 201 ' <a href="#" onclick="return clearRawId(this);">' 202 '<img src="%(img_src)s" ' 203 'width="10" height="10" alt="%(clear)s" title="%(clear)s" />' 204 '</a></strong>' % {'name': name, 205 'label': label, 206 'img_src': static('admin/img/icon_deletelink.gif'), 207 'clear': _("Clear")} 208 ) 209 else: 210 # a placeholder that will be filled in 211 # JavaScript dismissRelatedLookupPopup() 212 return ' <strong id="%s"></strong>' % name 213 183 214 184 215 class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 185 216 """ … … class ManyToManyRawIdWidget(ForeignKeyRawIdWidget): 201 232 def url_parameters(self): 202 233 return self.base_url_parameters() 203 234 204 def label_for_value(self, value): 205 return '' 235 def label_for_value(self, value, name): 236 if not value: 237 return '' 238 value = [int(v) for v in value.split(',')] 239 objs = self.rel.to._default_manager.filter(pk__in=value) 240 return ' <strong>%s</strong>' % ', '.join(truncate_words(obj, 14) for obj in objs) 206 241 207 242 def value_from_datadict(self, data, files, name): 208 243 value = data.get(name) -
tests/regressiontests/admin_widgets/tests.py
diff --git a/tests/regressiontests/admin_widgets/tests.py b/tests/regressiontests/admin_widgets/tests.py index 87e0309..786970b 100644
a b class ForeignKeyRawIdWidgetTest(DjangoTestCase): 292 292 w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 293 293 self.assertHTMLEqual( 294 294 conditional_escape(w.render('test', band.pk, attrs={})), 295 '<input type="text" name="test" value="%(bandpk)s" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/band/?t=id" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong >Linkin Park</strong>' % dict(admin_media_prefix(), bandpk=band.pk)295 '<input type="text" name="test" value="%(bandpk)s" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/band/?t=id" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong id="view_lookup_id_test"><a href="/widget_admin/admin_widgets/band/1/" onclick="return showRelatedObjectPopup(this);">Linkin Park</a> <a href="#" onclick="return clearRawId(this);"><img src="%(ADMIN_MEDIA_PREFIX)simg/icon_deletelink.gif" width="10" height="10" alt="Clear" title="Clear" /></a></strong>' % dict(admin_media_prefix(), bandpk=band.pk) 296 296 ) 297 297 298 298 def test_relations_to_non_primary_key(self): … … class ForeignKeyRawIdWidgetTest(DjangoTestCase): 307 307 w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 308 308 self.assertHTMLEqual( 309 309 w.render('test', core.parent_id, attrs={}), 310 '<input type="text" name="test" value="86" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Apple</strong>' % admin_media_prefix()310 u'<input type="text" name="test" value="86" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong id="view_lookup_id_test"><a href="/widget_admin/admin_widgets/inventory/1/" onclick="return showRelatedObjectPopup(this);">Apple</a> <a href="#" onclick="return clearRawId(this);"><img src="%(ADMIN_MEDIA_PREFIX)simg/icon_deletelink.gif" width="10" height="10" alt="Clear" title="Clear" /></a></strong>' % admin_media_prefix() 311 311 ) 312 312 313 313 def test_fk_related_model_not_in_admin(self): … … class ForeignKeyRawIdWidgetTest(DjangoTestCase): 320 320 w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 321 321 self.assertHTMLEqual( 322 322 conditional_escape(w.render('honeycomb_widget', big_honeycomb.pk, attrs={})), 323 '<input type="text" name="honeycomb_widget" value="%(hcombpk)s" /> <strong >Honeycomb object</strong>' % {'hcombpk': big_honeycomb.pk}323 '<input type="text" name="honeycomb_widget" value="%(hcombpk)s" /> <strong id="view_lookup_id_honeycomb_widget">Honeycomb object <a href="#" onclick="return clearRawId(this);"><img src="/static/admin/img/icon_deletelink.gif" width="10" height="10" alt="Clear" title="Clear" /></a></strong>' % {'hcombpk': big_honeycomb.pk} 324 324 ) 325 325 326 326 def test_fk_to_self_model_not_in_admin(self): … … class ForeignKeyRawIdWidgetTest(DjangoTestCase): 333 333 w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) 334 334 self.assertHTMLEqual( 335 335 conditional_escape(w.render('individual_widget', subject1.pk, attrs={})), 336 '<input type="text" name="individual_widget" value="%(subj1pk)s" /> <strong >Individual object</strong>' % {'subj1pk': subject1.pk}336 '<input type="text" name="individual_widget" value="%(subj1pk)s" /> <strong id="view_lookup_id_individual_widget">Individual object <a href="#" onclick="return clearRawId(this);"><img src="/static/admin/img/icon_deletelink.gif" width="10" height="10" alt="Clear" title="Clear" /></a></strong>' % {'subj1pk': subject1.pk} 337 337 ) 338 338 339 339 def test_proper_manager_for_label_lookup(self): … … class ForeignKeyRawIdWidgetTest(DjangoTestCase): 349 349 ) 350 350 self.assertHTMLEqual( 351 351 w.render('test', child_of_hidden.parent_id, attrs={}), 352 '<input type="text" name="test" value="93" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong >Hidden</strong>' % admin_media_prefix()352 '<input type="text" name="test" value="93" class="vForeignKeyRawIdAdminField" /><a href="/widget_admin/admin_widgets/inventory/?t=barcode" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong id="view_lookup_id_test"><a href="/widget_admin/admin_widgets/inventory/1/" onclick="return showRelatedObjectPopup(this);">Hidden</a> <a href="#" onclick="return clearRawId(this);"><img src="%(ADMIN_MEDIA_PREFIX)simg/icon_deletelink.gif" width="10" height="10" alt="Clear" title="Clear" /></a></strong>' % admin_media_prefix() 353 353 ) 354 354 355 355 … … class ManyToManyRawIdWidgetTest(DjangoTestCase): 365 365 w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site) 366 366 self.assertHTMLEqual( 367 367 conditional_escape(w.render('test', [m1.pk, m2.pk], attrs={})), 368 '<input type="text" name="test" value="%(m1pk)s,%(m2pk)s" class="vManyToManyRawIdAdminField" /><a href="/widget_admin/admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src=" /static/admin/img/selector-search.gif" width="16" height="16" alt="Lookup" /></a>' % dict(admin_media_prefix(), m1pk=m1.pk, m2pk=m2.pk)368 '<input type="text" name="test" value="%(m1pk)s,%(m2pk)s" class="vManyToManyRawIdAdminField" /><a href="/widget_admin/admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Chester, Mike</strong>' % dict(admin_media_prefix(), m1pk=m1.pk, m2pk=m2.pk) 369 369 ) 370 370 371 371 self.assertHTMLEqual( 372 372 conditional_escape(w.render('test', [m1.pk])), 373 '<input type="text" name="test" value="%(m1pk)s" class="vManyToManyRawIdAdminField" /><a href="/widget_admin/admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> ' % dict(admin_media_prefix(), m1pk=m1.pk)373 '<input type="text" name="test" value="%(m1pk)s" class="vManyToManyRawIdAdminField" /><a href="/widget_admin/admin_widgets/member/" class="related-lookup" id="lookup_id_test" onclick="return showRelatedObjectLookupPopup(this);"> <img src="%(ADMIN_MEDIA_PREFIX)simg/selector-search.gif" width="16" height="16" alt="Lookup" /></a> <strong>Chester</strong>' % dict(admin_media_prefix(), m1pk=m1.pk) 374 374 ) 375 375 376 376 self.assertEqual(w._has_changed(None, None), False) … … class ManyToManyRawIdWidgetTest(DjangoTestCase): 393 393 w = widgets.ManyToManyRawIdWidget(rel, widget_admin_site) 394 394 self.assertHTMLEqual( 395 395 conditional_escape(w.render('company_widget1', [c1.pk, c2.pk], attrs={})), 396 '<input type="text" name="company_widget1" value="%(c1pk)s,%(c2pk)s" /> ' % {'c1pk': c1.pk, 'c2pk': c2.pk}396 '<input type="text" name="company_widget1" value="%(c1pk)s,%(c2pk)s" /> <strong>Company object, Company object</strong>' % {'c1pk': c1.pk, 'c2pk': c2.pk} 397 397 ) 398 398 399 399 self.assertHTMLEqual( 400 400 conditional_escape(w.render('company_widget2', [c1.pk])), 401 '<input type="text" name="company_widget2" value="%(c1pk)s" /> ' % {'c1pk': c1.pk}401 '<input type="text" name="company_widget2" value="%(c1pk)s" /> <strong>Company object</strong>' % {'c1pk': c1.pk} 402 402 ) 403 403 404 404 class RelatedFieldWidgetWrapperTests(DjangoTestCase): … … class HorizontalVerticalFilterSeleniumChromeTests(HorizontalVerticalFilterSeleni 691 691 webdriver_class = 'selenium.webdriver.chrome.webdriver.WebDriver' 692 692 693 693 class HorizontalVerticalFilterSeleniumIETests(HorizontalVerticalFilterSeleniumFirefoxTests): 694 webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver' 695 No newline at end of file 694 webdriver_class = 'selenium.webdriver.ie.webdriver.WebDriver'