Skip to content

Commit 1048da4

Browse files
Merge pull request #5 from hartwork/issue-3-ease-use-of-select2-theme-bootstrap4
"bootstrap4" theme support (fixes #3)
2 parents f4419db + 3683a4e commit 1048da4

File tree

5 files changed

+268
-12
lines changed

5 files changed

+268
-12
lines changed

README.md

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@
22

33
This simple django app enables users to do a few tweaks to [Django's built-in autocomplete](https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.autocomplete_fields) feature.
44

5+
56
## Installation
7+
68
```bash
79
pip install django-simple-select2
810
```
11+
12+
913
## Usage
14+
15+
### `models.py`
16+
1017
```python
11-
# models.py
1218
class Publication(models.Model):
1319
name = models.CharField(max_length=100)
1420

@@ -32,8 +38,12 @@ class Article(models.Model):
3238

3339
def __str__(self):
3440
return self.headline
35-
36-
# admin.py
41+
```
42+
43+
44+
### `admin.py`
45+
46+
```python
3747
from django.contrib import admin
3848
from .models import Article
3949
from simple_select2 import Select2Admin, AutoCompleteSelect2, AutoCompleteSelect2Multiple
@@ -47,8 +57,12 @@ class ArticleModelAdmin(Select2Admin, admin.ModelAdmin):
4757

4858

4959
admin.site.register(Article, ArticleModelAdmin)
60+
```
61+
62+
63+
### `views.py`
5064

51-
#views.py
65+
```python
5266
from simple_select2 import AutoCompleteBaseView
5367
from .models import Reporter, Publication
5468

@@ -61,7 +75,7 @@ class ReporterView(AutoCompleteBaseView):
6175
class PublicationView(AutoCompleteBaseView):
6276
model = Publication
6377
search_fields = ('name',)
64-
78+
6579
#urls.py
6680
from django.urls import path
6781
from .views import ReporterView, PublicationView
@@ -71,9 +85,38 @@ urlpatterns = [
7185
path('publication/', PublicationView.as_view(), name='select2-publication-list'),
7286
...
7387
]
88+
```
7489

7590

76-
```
91+
## Settings
92+
93+
### `SIMPLE_SELECT2_THEME`
94+
95+
Sets the project-wide default [theme](https://select2.org/appearance#themes)
96+
to be used by Select2 for all widgets inheriting from `AutoCompleteSelect2Mixin`.
97+
Can be overridden per widget using parameter `theme`.
98+
99+
Supported values are:
100+
- `None` (or unset) will use theme `"admin-autocomplete"`. This is the default.
101+
- `"admin-autocomplete"` uses the theme of Django Admin.
102+
- `"bootstrap4"` uses a bundled copy of Takashi Kanemoto's [select2-bootstrap4-theme](https://github.com/ttskch/select2-bootstrap4-theme).
103+
Please note that this theme requires that you
104+
[pull in Bootstrap 4 CSS and JavaScript assets](https://getbootstrap.com/docs/4.0/getting-started/introduction/#quick-start)
105+
in your templates somewhere yourself.
106+
- `"classic"` uses the old classic theme of upstream Select2. Not much different from theme `"admin-autocomplete"`.
107+
- `"default"` uses the default upstream theme of Select2.
108+
109+
110+
### `SIMPLE_SELECT2_WIDTH`
111+
112+
Sets the project-wide default [width](https://select2.org/appearance#container-width)
113+
to be used by Select2 for all widgets inheriting from `AutoCompleteSelect2Mixin`.
114+
Can be overridden per widget using parameter `width`.
115+
116+
For supported values, please check the [official documentation of parameter `width` of Select2](https://select2.org/appearance#container-width).
117+
By default, django-simple-select2 does not enforce any width on Select2.
118+
77119

78120
## Demo
121+
79122
You will find a simple demo app here, [**simple-select2-demo**](https://github.com/jerinpetergeorge/simple-select2-demo)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2018 Takashi Kanemoto
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
.select2-container--bootstrap4 .select2-selection--single {
2+
height: calc(2.25rem + 2px) !important; }
3+
.select2-container--bootstrap4 .select2-selection--single .select2-selection__placeholder {
4+
color: #757575;
5+
line-height: 2.25rem; }
6+
.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow {
7+
position: absolute;
8+
top: 50%;
9+
right: 3px;
10+
width: 20px; }
11+
.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b {
12+
top: 60%;
13+
border-color: #343a40 transparent transparent transparent;
14+
border-style: solid;
15+
border-width: 5px 4px 0 4px;
16+
width: 0;
17+
height: 0;
18+
left: 50%;
19+
margin-left: -4px;
20+
margin-top: -2px;
21+
position: absolute; }
22+
.select2-container--bootstrap4 .select2-selection--single .select2-selection__rendered {
23+
line-height: 2.25rem; }
24+
25+
.select2-search--dropdown .select2-search__field {
26+
border: 1px solid #ced4da;
27+
border-radius: 0.25rem; }
28+
29+
.select2-results__message {
30+
color: #6c757d; }
31+
32+
.select2-container--bootstrap4 .select2-selection--multiple {
33+
min-height: calc(2.25rem + 2px) !important; }
34+
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__rendered {
35+
-webkit-box-sizing: border-box;
36+
box-sizing: border-box;
37+
list-style: none;
38+
margin: 0;
39+
padding: 0 5px;
40+
width: 100%; }
41+
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice {
42+
color: #343a40;
43+
border: 1px solid #bdc6d0;
44+
border-radius: 0.2rem;
45+
padding: 0;
46+
padding-right: 5px;
47+
cursor: pointer;
48+
float: left;
49+
margin-top: 0.3em;
50+
margin-right: 5px; }
51+
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove {
52+
color: #bdc6d0;
53+
font-weight: bold;
54+
margin-left: 3px;
55+
margin-right: 1px;
56+
padding-right: 3px;
57+
padding-left: 3px;
58+
float: left; }
59+
.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove:hover {
60+
color: #343a40; }
61+
62+
.select2-container {
63+
display: block; }
64+
.select2-container *:focus {
65+
outline: 0; }
66+
67+
.input-group .select2-container--bootstrap4 {
68+
-webkit-box-flex: 1;
69+
-ms-flex-positive: 1;
70+
flex-grow: 1; }
71+
72+
.input-group-prepend ~ .select2-container--bootstrap4 .select2-selection {
73+
border-top-left-radius: 0;
74+
border-bottom-left-radius: 0; }
75+
76+
.input-group > .select2-container--bootstrap4:not(:last-child) .select2-selection {
77+
border-top-right-radius: 0;
78+
border-bottom-right-radius: 0; }
79+
80+
.select2-container--bootstrap4 .select2-selection {
81+
background-color: #fff;
82+
border: 1px solid #ced4da;
83+
border-radius: 0.25rem;
84+
-webkit-transition: border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out;
85+
transition: border-color 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out;
86+
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
87+
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, -webkit-box-shadow 0.15s ease-in-out;
88+
width: 100%; }
89+
@media screen and (prefers-reduced-motion: reduce) {
90+
.select2-container--bootstrap4 .select2-selection {
91+
-webkit-transition: none;
92+
transition: none; } }
93+
94+
.select2-container--bootstrap4.select2-container--focus .select2-selection {
95+
border-color: #80bdff;
96+
-webkit-box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
97+
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); }
98+
99+
.select2-container--bootstrap4.select2-container--focus.select2-container--open .select2-selection {
100+
border-bottom: none;
101+
border-bottom-left-radius: 0;
102+
border-bottom-right-radius: 0; }
103+
104+
.select2-container--bootstrap4.select2-container--disabled .select2-selection, .select2-container--bootstrap4.select2-container--disabled.select2-container--focus .select2-selection {
105+
background-color: #e9ecef;
106+
cursor: not-allowed;
107+
border-color: #ced4da;
108+
-webkit-box-shadow: none;
109+
box-shadow: none; }
110+
111+
.select2-container--bootstrap4.select2-container--disabled .select2-search__field, .select2-container--bootstrap4.select2-container--disabled.select2-container--focus .select2-search__field {
112+
background-color: transparent; }
113+
114+
select.is-invalid ~ .select2-container--bootstrap4 .select2-selection,
115+
form.was-validated select:invalid ~ .select2-container--bootstrap4 .select2-selection {
116+
border-color: #dc3545; }
117+
118+
select.is-valid ~ .select2-container--bootstrap4 .select2-selection,
119+
form.was-validated select:valid ~ .select2-container--bootstrap4 .select2-selection {
120+
border-color: #28a745; }
121+
122+
.select2-container--bootstrap4 .select2-dropdown {
123+
border-color: #ced4da;
124+
border-top: none;
125+
border-top-left-radius: 0;
126+
border-top-right-radius: 0; }
127+
.select2-container--bootstrap4 .select2-dropdown.select2-dropdown--above {
128+
border-top: 1px solid #ced4da;
129+
border-top-left-radius: 0.25rem;
130+
border-top-right-radius: 0.25rem; }
131+
.select2-container--bootstrap4 .select2-dropdown .select2-results__option[aria-selected=true] {
132+
background-color: #e9ecef; }
133+
134+
.select2-container--bootstrap4 .select2-results__option--highlighted,
135+
.select2-container--bootstrap4 .select2-results__option--highlighted.select2-results__option[aria-selected=true] {
136+
background-color: #007bff;
137+
color: #f8f9fa; }
138+
139+
.select2-container--bootstrap4 .select2-results__option[role=group] {
140+
padding: 0; }
141+
142+
.select2-container--bootstrap4 .select2-results > .select2-results__options {
143+
max-height: 15em;
144+
overflow-y: auto; }
145+
146+
.select2-container--bootstrap4 .select2-results__group {
147+
padding: 6px;
148+
display: list-item;
149+
color: #6c757d; }
150+
151+
.select2-container--bootstrap4 .select2-selection__clear {
152+
width: 1.2em;
153+
height: 1.2em;
154+
line-height: 1.15em;
155+
padding-left: 0.3em;
156+
margin-top: 0.5em;
157+
border-radius: 100%;
158+
background-color: #6c757d;
159+
color: #f8f9fa;
160+
float: right;
161+
margin-right: 0.3em; }
162+
.select2-container--bootstrap4 .select2-selection__clear:hover {
163+
background-color: #343a40; }

simple_select2/static/simple_select2/select2-bootstrap4-theme-1.3.2/select2-bootstrap4.min.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

simple_select2/widgets.py

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,45 @@
1+
from django.conf import settings
12
from django.contrib.admin.widgets import AutocompleteMixin
3+
from django.forms import Media
24
from django.urls import reverse
35
from django import forms
46

7+
_BOOTSTRAP4_THEME_VERSION = '1.3.2'
8+
59

610
class AutoCompleteSelect2Mixin(AutocompleteMixin):
7-
def __init__(self, url, attrs=None, choices=(), using=None):
8-
self.url = url
9-
self.db = using
10-
self.choices = choices
11-
self.attrs = {} if attrs is None else attrs.copy()
11+
def __init__(self, url, theme=None, width=None, **kwargs):
12+
kwargs.setdefault('rel', None)
13+
kwargs.setdefault('admin_site', None)
14+
super().__init__(**kwargs)
15+
self.__url = url
16+
self.__theme = theme or getattr(settings, 'SIMPLE_SELECT2_THEME', None)
17+
self.__width = width or getattr(settings, 'SIMPLE_SELECT2_WIDTH', None)
18+
19+
def build_attrs(self, base_attrs, extra_attrs=None):
20+
attrs = super().build_attrs(base_attrs, extra_attrs=extra_attrs)
21+
if self.__theme is not None:
22+
attrs['data-theme'] = self.__theme
23+
if self.__width is not None:
24+
attrs['data-width'] = self.__width
25+
return attrs
1226

1327
def get_url(self):
14-
return reverse(self.url)
28+
return reverse(self.__url)
29+
30+
@property
31+
def media(self):
32+
original_media = super().media
33+
34+
if self.__theme != 'bootstrap4':
35+
return original_media
36+
37+
minified = '' if settings.DEBUG else '.min'
38+
return original_media + Media(css={
39+
'screen': (
40+
f'simple_select2/select2-bootstrap4-theme-{_BOOTSTRAP4_THEME_VERSION}/select2-bootstrap4{minified}.css',
41+
),
42+
})
1543

1644

1745
class AutoCompleteSelect2(AutoCompleteSelect2Mixin, forms.Select):

0 commit comments

Comments
 (0)