def get_i18n_name(lang_code): """Ensure lang_code is supported by Select2.""" lower_lang = lang_code.lower() split_lang = lang_code.split('-')[0] # Use the SELECT2_TRANSLATIONS if available if SELECT2_TRANSLATIONS: if lower_lang in SELECT2_TRANSLATIONS: return SELECT2_TRANSLATIONS.get(lower_lang) elif split_lang in SELECT2_TRANSLATIONS: return SELECT2_TRANSLATIONS.get(split_lang) # Otherwise fallback to manually checking if the static file exists if finders.find('admin/js/vendor/select2/i18n/%s.js' % lang_code): return lang_code elif finders.find('admin/js/vendor/select2/i18n/%s.js' % split_lang): return lang_code.split('-')[0]
def _get_media(self): """ Construct Media as a dynamic property. .. Note:: For more information visit https://docs.djangoproject.com/en/stable/topics/forms/media/#media-as-a-dynamic-property """ lang = get_language() i18n_name = None select2_js = (settings.SELECT2_JS,) if settings.SELECT2_JS else () select2_css = (settings.SELECT2_CSS,) if settings.SELECT2_CSS else () try: from django.contrib.admin.widgets import SELECT2_TRANSLATIONS i18n_name = SELECT2_TRANSLATIONS.get(lang) if i18n_name not in settings.SELECT2_I18N_AVAILABLE_LANGUAGES: i18n_name = None except ImportError: # TODO: select2 widget feature needs to be backported into Django 1.11 try: i = [x.lower() for x in settings.SELECT2_I18N_AVAILABLE_LANGUAGES].index(lang) i18n_name = settings.SELECT2_I18N_AVAILABLE_LANGUAGES[i] except ValueError: pass i18n_file = ('%s/%s.js' % (settings.SELECT2_I18N_PATH, i18n_name),) if i18n_name else () return forms.Media( js=select2_js + i18n_file + ('django_select2/django_select2.js',), css={'screen': select2_css} )
def media(self): media = super().media i18n_file = None i18n_name = SELECT2_TRANSLATIONS.get(get_language(), None) if i18n_name: i18n_file = "admin/js/vendor/select2/i18n/%s.js" % i18n_name extra_js = [ "admin/js/vendor/jquery/jquery.js", "admin/js/vendor/select2/select2.full.js", ] if i18n_file: extra_js.append(i18n_file) extra_js.extend([ "admin/js/jquery.init.js", "admin/js/autocomplete.js", "admin/js/autocomplete_filter.js", ]) extra_css = [ "admin/css/vendor/select2/select2.css", "admin/css/autocomplete.css", ] if django.VERSION >= (2, 2, 0, "final", 0): media._js_lists.append(extra_js) media._css_lists.append({"screen": extra_css}) else: media._js = OrderedSet(extra_js + media._js) media._css.setdefault("screen", []) media._css["screen"].extend(extra_css) return media
def media(self): """Return JS/CSS resources for the widget.""" extra = '' if settings.DEBUG else '.min' i18n_name = SELECT2_TRANSLATIONS.get(translation.get_language()) i18n_file = ('admin/js/vendor/select2/i18n/%s.js' % i18n_name, ) if i18n_name else () return forms.Media( js=( 'admin/js/vendor/jquery/jquery%s.js' % extra, 'autocomplete_light/jquery.init.js', 'admin/js/vendor/select2/select2.full%s.js' % extra, ) + i18n_file + ( 'autocomplete_light/autocomplete.init.js', 'autocomplete_light/forward.js', 'autocomplete_light/select2.js', 'autocomplete_light/jquery.post-setup.js', ), css={ 'screen': ( 'admin/css/vendor/select2/select2%s.css' % extra, 'admin/css/autocomplete.css', 'autocomplete_light/select2.css', ), }, )
def media(self): extra = "" if settings.DEBUG else ".min" i18n_name = SELECT2_TRANSLATIONS.get(get_language()) i18n_file = (("admin/js/vendor/select2/i18n/%s.js" % i18n_name, ) if i18n_name else ()) return forms.Media( js=( "admin/js/vendor/jquery/jquery%s.js" % extra, "admin/js/vendor/select2/select2.full%s.js" % extra, ) + i18n_file + ("admin/js/jquery.init.js", "admin/gestion/hierarchical-select.js"), css={ "screen": ("admin/css/vendor/select2/select2%s.css" % extra, ), }, )
class Media: extra = '' if settings.DEBUG else '.min' i18n_name = SELECT2_TRANSLATIONS.get(get_language()) i18n_file = ('admin/js/vendor/select2/i18n/%s.js' % i18n_name, ) if i18n_name else () js = ('admin/js/vendor/select2/select2.full%s.js' % extra, ) + i18n_file + ( 'admin/js/jquery.init.js', 'admin/js/autocomplete.js', 'js/autocomplete_filter_qs.js', ) css = { 'screen': ( 'admin/css/vendor/select2/select2%s.css' % extra, 'admin/css/autocomplete.css', 'css/autocomplete-fix.css', ), }
def media(self): extra = '' if settings.DEBUG else '.min' i18n_name = SELECT2_TRANSLATIONS.get(get_language()) i18n_file = ('admin/js/vendor/select2/i18n/%s.js' % i18n_name,) if i18n_name else () return forms.Media( js=('admin/js/vendor/jquery/jquery%s.js' % extra, 'admin/js/vendor/select2/select2.full%s.js' % extra, ) + i18n_file + ('admin/js/jquery.init.js', 'admin/js/autocomplete.js', 'adminfilters/adminfilters%s.js' % extra, ), css={ 'screen': ( 'admin/css/vendor/select2/select2%s.css' % extra, 'admin/css/autocomplete.css', ), }, )
def media(self): """ Construct Media as a dynamic property. .. Note:: For more information visit https://docs.djangoproject.com/en/stable/topics/forms/media/#media-as-a-dynamic-property """ lang = get_language() select2_js = (settings.SELECT2_JS, ) if settings.SELECT2_JS else () select2_css = (settings.SELECT2_CSS, ) if settings.SELECT2_CSS else () i18n_name = SELECT2_TRANSLATIONS.get(lang) if i18n_name not in settings.SELECT2_I18N_AVAILABLE_LANGUAGES: i18n_name = None i18n_file = (('%s/%s.js' % (settings.SELECT2_I18N_PATH, i18n_name), ) if i18n_name else ()) return forms.Media(js=select2_js + i18n_file + (static("js/django_select2.js"), ), css={'screen': select2_css})
def _get_media(self): """ Construct Media as a dynamic property. .. Note:: For more information visit https://docs.djangoproject.com/en/stable/topics/forms/media/#media-as-a-dynamic-property """ lang = get_language() select2_js = (settings.SELECT2_JS,) if settings.SELECT2_JS else () select2_css = (settings.SELECT2_CSS,) if settings.SELECT2_CSS else () i18n_name = SELECT2_TRANSLATIONS.get(lang) if i18n_name not in settings.SELECT2_I18N_AVAILABLE_LANGUAGES: i18n_name = None i18n_file = ('%s/%s.js' % (settings.SELECT2_I18N_PATH, i18n_name),) if i18n_name else () return forms.Media( js=select2_js + i18n_file + ('django_select2/django_select2.js',), css={'screen': select2_css} )
def media(self): extra = '' if settings.DEBUG else '.min' i18n_name = SELECT2_TRANSLATIONS.get(translation.get_language()) i18n_file = ('admin/js/vendor/select2/i18n/%s.js' % i18n_name,) if i18n_name else () return forms.Media( js=( 'admin/js/vendor/jquery/jquery%s.js' % extra, 'autocomplete_light/jquery.init.js', 'admin/js/vendor/select2/select2.full%s.js' % extra, ) + i18n_file + ( 'autocomplete_light/autocomplete.init.js', 'autocomplete_light/forward.js', 'autocomplete_light/select2_create_modal.js', # 后期改的 'autocomplete_light/jquery.post-setup.js', ), css={ 'screen': ( 'admin/css/vendor/select2/select2%s.css' % extra, 'admin/css/autocomplete.css', 'css/materialize-select2.css', # 后期自己加上 'autocomplete_light/select2.css', ), }, )
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.i18n_name = SELECT2_TRANSLATIONS.get(get_language())
class TestSelect2Mixin: url = reverse("select2_widget") form = forms.AlbumSelect2WidgetForm() multiple_form = forms.AlbumSelect2MultipleWidgetForm() widget_cls = Select2Widget def test_initial_data(self, genres): genre = genres[0] form = self.form.__class__(initial={"primary_genre": genre.pk}) assert str(genre) in form.as_p() def test_initial_form_class(self): widget = self.widget_cls(attrs={"class": "my-class"}) assert "my-class" in widget.render("name", None) assert "django-select2" in widget.render("name", None) @pytest.mark.parametrize("code,name", SELECT2_TRANSLATIONS.items()) def test_lang_attr(self, code, name): translation.activate(code) widget = self.widget_cls() assert f'lang="{name}"' in widget.render("name", None) def test_allow_clear(self, db): required_field = self.form.fields["artist"] assert required_field.required is True assert 'data-allow-clear="true"' not in required_field.widget.render( "artist", None) assert 'data-allow-clear="false"' in required_field.widget.render( "artist", None) assert '<option value=""></option>' not in required_field.widget.render( "artist", None) not_required_field = self.form.fields["primary_genre"] assert not_required_field.required is False assert 'data-allow-clear="true"' in not_required_field.widget.render( "primary_genre", None) assert 'data-allow-clear="false"' not in not_required_field.widget.render( "primary_genre", None) assert "data-placeholder" in not_required_field.widget.render( "primary_genre", None) assert '<option value=""></option>' in not_required_field.widget.render( "primary_genre", None) def test_no_js_error(self, db, live_server, driver): driver.get(live_server + self.url) with pytest.raises(NoSuchElementException): error = driver.find_element_by_xpath("//body[@JSError]") pytest.fail(error.get_attribute("JSError")) def test_selecting(self, db, live_server, driver): driver.get(live_server + self.url) with pytest.raises(NoSuchElementException): driver.find_element_by_css_selector(".select2-results") elem = driver.find_element_by_css_selector(".select2-selection") elem.click() results = driver.find_element_by_css_selector(".select2-results") assert results.is_displayed() is True elem = results.find_element_by_css_selector(".select2-results__option") elem.click() with pytest.raises(NoSuchElementException): error = driver.find_element_by_xpath("//body[@JSError]") pytest.fail(error.get_attribute("JSError")) def test_data_url(self): with pytest.raises(ValueError): HeavySelect2Widget() widget = HeavySelect2Widget(data_url="/foo/bar") assert widget.get_url() == "/foo/bar" def test_empty_option(self, db): # Empty options is only required for single selects # https://select2.github.io/options.html#allowClear single_select = self.form.fields["primary_genre"] assert single_select.required is False assert '<option value=""></option>' in single_select.widget.render( "primary_genre", None) multiple_select = self.multiple_form.fields["featured_artists"] assert multiple_select.required is False assert multiple_select.widget.allow_multiple_selected output = multiple_select.widget.render("featured_artists", None) assert '<option value=""></option>' not in output assert 'data-placeholder=""' in output def test_i18n(self): translation.activate("de") assert tuple(Select2Widget().media._js) == ( f"https://cdnjs.cloudflare.com/ajax/libs/select2/{settings.SELECT2_LIB_VERSION}/js/select2.min.js", f"https://cdnjs.cloudflare.com/ajax/libs/select2/{settings.SELECT2_LIB_VERSION}/js/i18n/de.js", "django_select2/django_select2.js", ) translation.activate("en") assert tuple(Select2Widget().media._js) == ( f"https://cdnjs.cloudflare.com/ajax/libs/select2/{settings.SELECT2_LIB_VERSION}/js/select2.min.js", f"https://cdnjs.cloudflare.com/ajax/libs/select2/{settings.SELECT2_LIB_VERSION}/js/i18n/en.js", "django_select2/django_select2.js", ) translation.activate("00") assert tuple(Select2Widget().media._js) == ( f"https://cdnjs.cloudflare.com/ajax/libs/select2/{settings.SELECT2_LIB_VERSION}/js/select2.min.js", "django_select2/django_select2.js", ) translation.activate("sr-cyrl") assert tuple(Select2Widget().media._js) == ( f"https://cdnjs.cloudflare.com/ajax/libs/select2/{settings.SELECT2_LIB_VERSION}/js/select2.min.js", f"https://cdnjs.cloudflare.com/ajax/libs/select2/{settings.SELECT2_LIB_VERSION}/js/i18n/sr-Cyrl.js", "django_select2/django_select2.js", ) pytest.importorskip("django", minversion="2.0.4") translation.activate("zh-hans") assert tuple(Select2Widget().media._js) == ( f"https://cdnjs.cloudflare.com/ajax/libs/select2/{settings.SELECT2_LIB_VERSION}/js/select2.min.js", f"https://cdnjs.cloudflare.com/ajax/libs/select2/{settings.SELECT2_LIB_VERSION}/js/i18n/zh-CN.js", "django_select2/django_select2.js", ) translation.activate("zh-hant") assert tuple(Select2Widget().media._js) == ( f"https://cdnjs.cloudflare.com/ajax/libs/select2/{settings.SELECT2_LIB_VERSION}/js/select2.min.js", f"https://cdnjs.cloudflare.com/ajax/libs/select2/{settings.SELECT2_LIB_VERSION}/js/i18n/zh-TW.js", "django_select2/django_select2.js", ) def test_theme_setting(self, settings): settings.SELECT2_THEME = "classic" widget = self.widget_cls() assert 'data-theme="classic"' in widget.render("name", None)
class TestHeavySelect2Mixin(TestSelect2Mixin): url = reverse("heavy_select2_widget") form = forms.HeavySelect2WidgetForm(initial={"primary_genre": 1}) widget_cls = HeavySelect2Widget def test_initial_data(self): assert "One" in self.form.as_p() def test_initial_form_class(self): widget = self.widget_cls(data_view="heavy_data_1", attrs={"class": "my-class"}) assert "my-class" in widget.render("name", None) assert "django-select2" in widget.render("name", None) assert "django-select2-heavy" in widget.render("name", None), widget.render( "name", None) @pytest.mark.parametrize("code,name", SELECT2_TRANSLATIONS.items()) def test_lang_attr(self, code, name): translation.activate(code) widget = self.widget_cls(data_view="heavy_data_1") assert f'lang="{name}"' in widget.render("name", None) def test_selected_option(self, db): not_required_field = self.form.fields["primary_genre"] assert not_required_field.required is False assert ('<option value="1" selected="selected">One</option>' in not_required_field.widget.render("primary_genre", 1) or '<option value="1" selected>One</option>' in not_required_field.widget.render( "primary_genre", 1)), (not_required_field.widget.render( "primary_genre", 1)) def test_many_selected_option(self, db, genres): field = HeavySelect2MultipleWidgetForm().fields["genres"] field.widget.choices = NUMBER_CHOICES widget_output = field.widget.render("genres", [1, 2]) selected_option = ( '<option value="{pk}" selected="selected">{value}</option>'.format( pk=1, value="One")) selected_option_a = '<option value="{pk}" selected>{value}</option>'.format( pk=1, value="One") selected_option2 = ( '<option value="{pk}" selected="selected">{value}</option>'.format( pk=2, value="Two")) selected_option2a = '<option value="{pk}" selected>{value}</option>'.format( pk=2, value="Two") assert (selected_option in widget_output or selected_option_a in widget_output), widget_output assert selected_option2 in widget_output or selected_option2a in widget_output def test_multiple_widgets(self, db, live_server, driver): driver.get(live_server + self.url) with pytest.raises(NoSuchElementException): driver.find_element_by_css_selector(".select2-results") elem1, elem2 = driver.find_elements_by_css_selector( ".select2-selection") elem1.click() search1 = driver.find_element_by_css_selector(".select2-search__field") search1.send_keys("fo") result1 = (WebDriverWait(driver, 60).until( expected_conditions.presence_of_element_located( (By.CSS_SELECTOR, ".select2-results li:first-child"))).text) elem2.click() search2 = driver.find_element_by_css_selector(".select2-search__field") search2.send_keys("fo") result2 = (WebDriverWait(driver, 60).until( expected_conditions.presence_of_element_located( (By.CSS_SELECTOR, ".select2-results li:first-child"))).text) assert result1 != result2 with pytest.raises(NoSuchElementException): error = driver.find_element_by_xpath("//body[@JSError]") pytest.fail(error.get_attribute("JSError")) def test_get_url(self): widget = self.widget_cls(data_view="heavy_data_1", attrs={"class": "my-class"}) assert isinstance(widget.get_url(), str) def test_can_not_pickle(self): widget = self.widget_cls(data_view="heavy_data_1", attrs={"class": "my-class"}) class NoPickle: pass widget.no_pickle = NoPickle() with pytest.raises(NotImplementedError): widget.set_to_cache() def test_theme_setting(self, settings): settings.SELECT2_THEME = "classic" widget = self.widget_cls(data_view="heavy_data_1") assert 'data-theme="classic"' in widget.render("name", None)
def __init__(self, admin_site, attrs=None, choices=(), using=None): self.admin_site = admin_site self.db = using self.choices = choices self.attrs = {} if attrs is None else attrs.copy() self.i18n_name = SELECT2_TRANSLATIONS.get(get_language())