django-unfold 0.66.0__py3-none-any.whl → 0.67.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-unfold
3
- Version: 0.66.0
3
+ Version: 0.67.0
4
4
  Summary: Modern Django admin theme for seamless interface development
5
5
  License: MIT
6
6
  License-File: LICENSE.md
@@ -16,14 +16,14 @@ unfold/contrib/filters/admin/choice_filters.py,sha256=wI_m5k8SLwHkWoFeCPvI0bN_Ru
16
16
  unfold/contrib/filters/admin/datetime_filters.py,sha256=cVari_7jsfeYxJoRBhcAUOr6v9XdtDtMuMs-S1Irafo,7757
17
17
  unfold/contrib/filters/admin/dropdown_filters.py,sha256=exiIyU6c_as7XBJsaAPPx5b8eY3IDbuCFGPJu1b0ux4,3856
18
18
  unfold/contrib/filters/admin/mixins.py,sha256=Z8BrdqbnjM1Ldr7qfhb6aWeOXKc5NqUgp-1NDU7SqS4,5839
19
- unfold/contrib/filters/admin/numeric_filters.py,sha256=8GNmesgMmMIfEZb2IrGbaBoJuvB2FpIc7wPIPBpHat4,6420
19
+ unfold/contrib/filters/admin/numeric_filters.py,sha256=V2yKPngFQ-PjpaE-VG2CK4jcJ-UZylEhtgSXRGx_MxQ,6490
20
20
  unfold/contrib/filters/admin/text_filters.py,sha256=19cOEGpSaXafcM8QuGiYaWmNi5UIQnCXEhKG-vCTfe8,2088
21
21
  unfold/contrib/filters/apps.py,sha256=wEySJy0gMLzFLb9XNKE-RexiO05X7NaQ5QmxZyziJ_k,136
22
- unfold/contrib/filters/forms.py,sha256=xROYON0ZaTLOE7gIhHXEgDAcYz0eY6LO2uxc3oXzfcA,8097
22
+ unfold/contrib/filters/forms.py,sha256=cebAmMPKtofdwvUhAVaoP5V3rNhwYe0Df5k06TJwZfo,8560
23
23
  unfold/contrib/filters/static/unfold/filters/css/nouislider/LICENSE,sha256=DR_G6Ykr-xlGx4DwQFeKTRcGAYL3ch33e44GisGdHOQ,1069
24
24
  unfold/contrib/filters/static/unfold/filters/css/nouislider/nouislider.min.css,sha256=rddL_jOGGVEY6wR-aw0VYovAfz5fPeAIsulrlSNb1hc,4221
25
25
  unfold/contrib/filters/static/unfold/filters/js/DateTimeShortcuts.js,sha256=jgFNBDf6aHvUlyv0LEDHggXO-xA8pWOCWFWcVupdA30,19332
26
- unfold/contrib/filters/static/unfold/filters/js/admin-numeric-filter.js,sha256=nTkiiJk4Abn9d6KigxPSEsereFhFq-v5n_boiiY1eII,1668
26
+ unfold/contrib/filters/static/unfold/filters/js/admin-numeric-filter.js,sha256=TnLzgMRzcePLHSMpvwCEA8CowifobGuCIS6IXRAU5XM,2363
27
27
  unfold/contrib/filters/static/unfold/filters/js/nouislider/LICENSE,sha256=DR_G6Ykr-xlGx4DwQFeKTRcGAYL3ch33e44GisGdHOQ,1069
28
28
  unfold/contrib/filters/static/unfold/filters/js/nouislider/nouislider.min.js,sha256=aIEt5UlLNnEv4-HPyxcLqu9dTS7gXiMm35Mm0rFmQ0Q,26683
29
29
  unfold/contrib/filters/static/unfold/filters/js/wnumb/LICENSE,sha256=ifeAa0-l35lCSesni0e-3xcD2BXwP7GXG6TdQiMW16I,1069
@@ -33,7 +33,7 @@ unfold/contrib/filters/templates/unfold/filters/filters_datetime_range.html,sha2
33
33
  unfold/contrib/filters/templates/unfold/filters/filters_field.html,sha256=UTlSZlpg-gAc_a-EJLLF0NI_ofuSHQ2kMMoAs99nL2E,164
34
34
  unfold/contrib/filters/templates/unfold/filters/filters_numeric_range.html,sha256=TnklQxXhe17UaImoiHahhtN6d1xVdXt2dhIMQESJY68,661
35
35
  unfold/contrib/filters/templates/unfold/filters/filters_numeric_single.html,sha256=uELVrDzFgmzGwkm37SpZeXXbfpijDnSBIJVtf6evWjM,598
36
- unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html,sha256=ihRdegeKkP2R3XQ_Z3_wujkjnc7ZByGqhfuDw4zjtNU,1880
36
+ unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html,sha256=82H0q9Bta_ng4k6BYpV5ECspmBwqAUXnVGKdrEOLc18,1165
37
37
  unfold/contrib/forms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
38
  unfold/contrib/forms/apps.py,sha256=Di0TMzVuRpVxLG-8Bjdq5ALCSf5r7u2xVhD0jU6H5Sc,132
39
39
  unfold/contrib/forms/static/unfold/forms/css/trix/LICENSE,sha256=-g0UVDdcvHcBvBPZFsOuceYTuK5xgyFkHmeOCUCTk8Q,1053
@@ -90,7 +90,7 @@ unfold/dataclasses.py,sha256=XDQp7fcvto7YC8A68tc6TUhXY7s3je9nm3AVUdxrJ7Y,859
90
90
  unfold/decorators.py,sha256=jPiYFy1p0WGFn68VZhAZkYCPDF7argb9SDFaH6aemHk,4922
91
91
  unfold/enums.py,sha256=9sTfyEycMWeoGPBa-ft6ZhQGnW1vkFg108RMBVf9nko,187
92
92
  unfold/exceptions.py,sha256=gcCj1ox61E137bk_0Cqy4YC3SttdPgB-fiJUqpmyHSE,43
93
- unfold/fields.py,sha256=wvkdeMCIYs3vNB_QDtRo191tXoYVrP-uRFfzFCTYY3c,7314
93
+ unfold/fields.py,sha256=qdnwYbl2NXbTdv1S_nct08UBWJTvoQ2hIrnzNxahJfg,8378
94
94
  unfold/forms.py,sha256=0u4TFw7oQ96S7njzJ2G79Qzt1X-4P4px-kfMgjVt49o,7762
95
95
  unfold/layout.py,sha256=Q-dFTA6UlvvPCA4PsGyTkHQmBLO7PL56xBfZi-bdt0c,1459
96
96
  unfold/mixins/__init__.py,sha256=YlhoDs9Y_DXQ8Ejr3enxuHMS1-Ij9fwukxNwpeOS4Co,190
@@ -105,7 +105,7 @@ unfold/static/admin/js/admin/RelatedObjectLookups.js,sha256=ubKKhWmX_QborwPnaLHu
105
105
  unfold/static/admin/js/inlines.js,sha256=UXtFzCWHZWIJbxRghlNsNsz8HuRHjcaH1Mvb5e6uJms,16222
106
106
  unfold/static/unfold/css/simplebar/LICENSE,sha256=okNJf6UFl2NrEiC4iqORNBa16IKgUgV88acdcl9FbtY,1081
107
107
  unfold/static/unfold/css/simplebar/simplebar.css,sha256=5LLaEM11pKi6JFCOLt4XKuZxTpT9rpdq_tNlaQytFlU,4647
108
- unfold/static/unfold/css/styles.css,sha256=MZEBfoBM6rUi0pkIoQw0hi2lChPsdCFIchyBOm4oF8c,211708
108
+ unfold/static/unfold/css/styles.css,sha256=4JvNtrvUk6tlpGSyQpnbxCCa3YPMmyKnSqEDUVT0-Po,211751
109
109
  unfold/static/unfold/fonts/inter/Inter-Bold.woff2,sha256=-oiBJ7baAVtlVp8DUfO1w5GtkokElR8cIOn4RiqNleo,114840
110
110
  unfold/static/unfold/fonts/inter/Inter-Medium.woff2,sha256=D_PpRhThST61VjFP0keubEqFp3g7TMhr5TmUDPg_Kkg,114348
111
111
  unfold/static/unfold/fonts/inter/Inter-Regular.woff2,sha256=4G9rG8VTqupORmgCPtCrChRxKcMQf1Ebx9A9NhsK4IU,111268
@@ -121,15 +121,15 @@ unfold/static/unfold/js/alpine/alpine.js,sha256=PtHu0lJIiSHfZeNj1nFd6wTX-Squ255S
121
121
  unfold/static/unfold/js/alpine/alpine.persist.js,sha256=jFBwr6faTqqhp3sVi4_VTxJ0FpaF9YGZN1ZGLl_5QYM,837
122
122
  unfold/static/unfold/js/alpine/alpine.resize.js,sha256=mXR2L6neT584cfNLY5_imDq5DKjW1noXys7fhb1yxY4,703
123
123
  unfold/static/unfold/js/alpine/alpine.sort.js,sha256=q6LxgConwu8M8R03mZSBcsKwJv6fF7oomP8sqLxVQ0w,37891
124
- unfold/static/unfold/js/app.js,sha256=rz5y-wOzUpXN1Gk23bot3XMyB6P3rTSSz6kqdDtuyMU,14775
124
+ unfold/static/unfold/js/app.js,sha256=r04hhe9FYimSvd_SLbP6AwgjaxE2HioFG3YLYaFH4YU,16282
125
125
  unfold/static/unfold/js/chart/LICENSE,sha256=QahKosq6ZF-WahjZwgVrc-bTqB2AvABGvAARomNNTM4,1093
126
126
  unfold/static/unfold/js/chart/chart.js,sha256=22W6cFERR-CElMOKRgMMicueMVP0Vf7FBEBYH8Z8tCk,200633
127
127
  unfold/static/unfold/js/htmx/LICENSE,sha256=09JFb3ZBTyRWEEZg69Za_xwEzXlmuUK9q9Y_PNsxajg,642
128
128
  unfold/static/unfold/js/htmx/htmx.js,sha256=acrv0NqSJpBm5yXX_hdeJrnVDJYuMFZFnAxHcVTNudM,50918
129
- unfold/static/unfold/js/select2.init.js,sha256=E1BhZ_a16_wxMb3zFq346HIrzvfQz8PRSB_o5CH_i2E,1196
129
+ unfold/static/unfold/js/select2.init.js,sha256=SeUUXgwLi26Tmh1Sgl3al4WeqlvmbZgixmTtwhJMMq0,1009
130
130
  unfold/static/unfold/js/simplebar/LICENSE,sha256=okNJf6UFl2NrEiC4iqORNBa16IKgUgV88acdcl9FbtY,1081
131
131
  unfold/static/unfold/js/simplebar/simplebar.js,sha256=t-uG1FAD6ZoiMeN--wac0XRS7SxoDVG6zvRnGuEp7X8,27176
132
- unfold/styles.css,sha256=hNU0840jnbJB20nLuE12sbKX3jCqjWR76mmsLN9uZic,21739
132
+ unfold/styles.css,sha256=6-pbdH8mHbV60EZ8RUR_gxzI6IN4-CaYbKZuzEslX7A,21608
133
133
  unfold/templates/admin/actions.html,sha256=iuuubcAILkOoYBgV6cpXqFIyZUh4zMqyFp0JaDFlPKU,3096
134
134
  unfold/templates/admin/app_index.html,sha256=hcXcaEwqKYTaClnGzlBEsTzy3YJn_37AiFs4YVbvX8A,585
135
135
  unfold/templates/admin/app_list.html,sha256=-DEZKFdmkdTq3rix_cgZurPZ1r8PHg5pBL3i7ZtzVdI,2972
@@ -162,7 +162,7 @@ unfold/templates/registration/logged_out.html,sha256=ytjIz3abnpERwUp1F8zn89Hyrim
162
162
  unfold/templates/registration/password_change_done.html,sha256=TjzRQ476BNkz3To2S7MhEXxA-zoqCI8Op_FjY0cRod0,364
163
163
  unfold/templates/registration/password_change_form.html,sha256=E9fRkSh7n5N7UQIy0oWpcvI1mVPQ0nYGlBrM_WTi9kw,1517
164
164
  unfold/templates/unfold/components/button.html,sha256=oJEamHBxDIjoQ1xqWuJWDMY5ItUo8jpkZrqFp_cCH5U,933
165
- unfold/templates/unfold/components/card.html,sha256=ntmFJcHWDQ1M6Xp9mE9BpIBeOfV-huSayDqz1Ajnd0k,1410
165
+ unfold/templates/unfold/components/card.html,sha256=inSlz0IbriTQwA-I9sAa8A15NAfjqOWRka28vB-Eu_Q,1565
166
166
  unfold/templates/unfold/components/chart/bar.html,sha256=nDdDCUXvFd793OpNgNPQo0vBmvYngMsQyPHVTf1vfOw,297
167
167
  unfold/templates/unfold/components/chart/cohort.html,sha256=L00WR-igYv0C3t2yT_nZqeI-M5gVHpoaGv5RooRojqU,2402
168
168
  unfold/templates/unfold/components/chart/line.html,sha256=DHaZUFTlCs5cX7ioYdTzoN4ITHWNcEoNSUp7v3hlo_E,298
@@ -171,7 +171,7 @@ unfold/templates/unfold/components/flex.html,sha256=_hBsQLJ6-7MfEfXNp5Wy-ykNtPMn
171
171
  unfold/templates/unfold/components/icon.html,sha256=Qlhcf41FOwNVJ-nvA0RJ_Dn6JW6PUFXO6tOR3Xtf6e8,99
172
172
  unfold/templates/unfold/components/layer.html,sha256=c2EY2rr64rJ5BPj97UdFAJTNWAommGoYL9J8gmjzEPE,15
173
173
  unfold/templates/unfold/components/navigation.html,sha256=0imW9pQs9kUZy2iROeAsGJDXC5tMRq9ABRcN85fJPeQ,866
174
- unfold/templates/unfold/components/progress.html,sha256=W55ByXiM-Ig_3fcpsZAG8N3HjQAl60sl7XsLsIZABrA,1001
174
+ unfold/templates/unfold/components/progress.html,sha256=voyLSflK08x7SP9mdsEixAsGiZj7YVfnZlfqntdw8ok,1480
175
175
  unfold/templates/unfold/components/separator.html,sha256=yvHywT_MFkx5dNC2K53OFHRGxLDsEjRpptujXyGeoTY,168
176
176
  unfold/templates/unfold/components/table.html,sha256=5Ghmaw3mHhKOlBKKRBfhmSx0-HkRx1sHpX6NDItgdv4,7911
177
177
  unfold/templates/unfold/components/text.html,sha256=-GjxvdiaBQIaNfPSzT6SSIwnc3R27FkSDQMoF3FDPso,102
@@ -204,7 +204,8 @@ unfold/templates/unfold/helpers/edit_inline/tabular_title.html,sha256=2sk1TRzpmw
204
204
  unfold/templates/unfold/helpers/empty_results.html,sha256=zN1XM6_9_Oj-inMZlDxEnicYfBRr4HhwS9ODAnMiRYc,1947
205
205
  unfold/templates/unfold/helpers/field.html,sha256=KEs1SQRxzJ0x11zithlxVyv5zfQ9a_XGoJJ9AiWk1Vc,1038
206
206
  unfold/templates/unfold/helpers/field_readonly.html,sha256=4qtXjWE7SA2qZSTYLOv0lT4pQfD0TE34mvWQJY7jhS8,237
207
- unfold/templates/unfold/helpers/field_readonly_value.html,sha256=FI_CFEsCN7ELQux9gF-IaZ7nT7jyzidqwR2Med-E52g,504
207
+ unfold/templates/unfold/helpers/field_readonly_value.html,sha256=dQHLb3eWeTZnXVzT8vaCbFNb4H9NwwNAv3qOKpOfDtM,531
208
+ unfold/templates/unfold/helpers/field_readonly_value_file.html,sha256=8P-4BO6eH6VfxihDsBj8vFsiMZsloaeoiDYgP3CYUIY,709
208
209
  unfold/templates/unfold/helpers/fieldset_row.html,sha256=LriorPLXU4VmqstjX1oBc3T49H8CbhCrRxwQ7YfUSkI,1219
209
210
  unfold/templates/unfold/helpers/fieldset_row_checkbox.html,sha256=z4aRab--zJS2PC0jfKPez85IptKGRrqgkPpwW6_IKoo,1467
210
211
  unfold/templates/unfold/helpers/fieldset_row_field.html,sha256=cqLT1fHsCCszOHxvYlDFDTAd-6RRoOjdqfdBdhFgHOo,647
@@ -304,7 +305,7 @@ unfold/typing.py,sha256=i7LM2LiwYTAjT5-OLDUPVn5b9X-DMmHnjlZG2toWwSE,692
304
305
  unfold/utils.py,sha256=UY7ZvkQ6KXkY0OkThppZ1k1HggyUhV_2bZok-HpFBDA,6827
305
306
  unfold/views.py,sha256=SA6mtv3aJD861-aL5VNreQUP7GRZH6hK_60MChjm2MM,1641
306
307
  unfold/widgets.py,sha256=nu2oqcKhs3lhj9ueYfs3BqDzZT5raAE6jeAEgU4WrHE,24751
307
- django_unfold-0.66.0.dist-info/METADATA,sha256=03YKKQ-HAzpxOxPlLKN9ps2rYqatp9HZf_cJpjjVXM0,10074
308
- django_unfold-0.66.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
309
- django_unfold-0.66.0.dist-info/licenses/LICENSE.md,sha256=Ltk_quRyyvV3J5v3brtOqmibeZSw2Hrb8bY1W3ya0Ik,1077
310
- django_unfold-0.66.0.dist-info/RECORD,,
308
+ django_unfold-0.67.0.dist-info/METADATA,sha256=HaIyDsX13qf8nRgmZqiECi0mT_zloMaF5dTWpuNkURk,10074
309
+ django_unfold-0.67.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
310
+ django_unfold-0.67.0.dist-info/licenses/LICENSE.md,sha256=Ltk_quRyyvV3J5v3brtOqmibeZSw2Hrb8bY1W3ya0Ik,1077
311
+ django_unfold-0.67.0.dist-info/RECORD,,
@@ -179,6 +179,8 @@ class SliderNumericFilter(RangeNumericFilter):
179
179
  ),
180
180
  "form": self.form_class(
181
181
  name=self.parameter_name,
182
+ min=min_value,
183
+ max=max_value,
182
184
  data={
183
185
  self.parameter_name + "_from": self.used_parameters.get(
184
186
  self.parameter_name + "_from", min_value
@@ -59,7 +59,11 @@ class AutocompleteDropdownForm(forms.Form):
59
59
  label=label,
60
60
  required=False,
61
61
  queryset=field.remote_field.model.objects,
62
- widget=self.widget(field, model_admin.admin_site),
62
+ widget=self.widget(
63
+ field,
64
+ model_admin.admin_site,
65
+ attrs={"class": "unfold-filter-autocomplete"},
66
+ ),
63
67
  )
64
68
 
65
69
  class Media:
@@ -175,22 +179,39 @@ class SingleNumericForm(forms.Form):
175
179
 
176
180
 
177
181
  class RangeNumericForm(forms.Form):
178
- def __init__(self, name: str, *args, **kwargs) -> None:
182
+ def __init__(
183
+ self, name: str, min: float = None, max: float = None, *args, **kwargs
184
+ ) -> None:
179
185
  self.name = name
180
186
  super().__init__(*args, **kwargs)
181
187
 
188
+ min_max = {}
189
+
190
+ if min:
191
+ min_max["min"] = min
192
+ if max:
193
+ min_max["max"] = max
194
+
182
195
  self.fields[self.name + "_from"] = forms.FloatField(
183
196
  label="",
184
197
  required=False,
185
198
  widget=forms.NumberInput(
186
- attrs={"placeholder": _("From"), "class": " ".join(INPUT_CLASSES)}
199
+ attrs={
200
+ "placeholder": _("From"),
201
+ "class": " ".join(INPUT_CLASSES),
202
+ **min_max,
203
+ }
187
204
  ),
188
205
  )
189
206
  self.fields[self.name + "_to"] = forms.FloatField(
190
207
  label="",
191
208
  required=False,
192
209
  widget=forms.NumberInput(
193
- attrs={"placeholder": _("To"), "class": " ".join(INPUT_CLASSES)}
210
+ attrs={
211
+ "placeholder": _("To"),
212
+ "class": " ".join(INPUT_CLASSES),
213
+ **min_max,
214
+ }
194
215
  ),
195
216
  )
196
217
 
@@ -1,35 +1,69 @@
1
- document.addEventListener('DOMContentLoaded', function() {
2
- Array.from(document.getElementsByClassName('admin-numeric-filter-slider')).forEach(function(slider) {
3
- if (Array.from(slider.classList).includes("noUi-target")) {
4
- return;
5
- }
1
+ document.addEventListener("DOMContentLoaded", function () {
2
+ Array.from(
3
+ document.getElementsByClassName("admin-numeric-filter-slider")
4
+ ).forEach(function (slider) {
5
+ if (Array.from(slider.classList).includes("noUi-target")) {
6
+ return;
7
+ }
6
8
 
7
- var from = parseFloat(slider.closest('.admin-numeric-filter-wrapper').querySelectorAll('.admin-numeric-filter-wrapper-group input')[0].value);
8
- var to = parseFloat(slider.closest('.admin-numeric-filter-wrapper').querySelectorAll('.admin-numeric-filter-wrapper-group input')[1].value);
9
+ const fromInput = slider
10
+ .closest(".admin-numeric-filter-wrapper")
11
+ .querySelectorAll(".admin-numeric-filter-wrapper-group input")[0];
9
12
 
10
- noUiSlider.create(slider, {
11
- start: [from, to],
12
- step: parseFloat(slider.getAttribute('data-step')),
13
- connect: true,
14
- format: wNumb({
15
- decimals: parseFloat(slider.getAttribute('data-decimals'))
16
- }),
17
- range: {
18
- 'min': parseFloat(slider.getAttribute('data-min')),
19
- 'max': parseFloat(slider.getAttribute('data-max'))
20
- }
21
- });
13
+ const toInput = slider
14
+ .closest(".admin-numeric-filter-wrapper")
15
+ .querySelectorAll(".admin-numeric-filter-wrapper-group input")[1];
22
16
 
23
- slider.noUiSlider.on('update', function(values, handle) {
24
- var parent = this.target.closest('.admin-numeric-filter-wrapper');
25
- var from = parent.querySelectorAll('.admin-numeric-filter-wrapper-group input')[0];
26
- var to = parent.querySelectorAll('.admin-numeric-filter-wrapper-group input')[1];
17
+ noUiSlider.create(slider, {
18
+ start: [parseFloat(fromInput.value), parseFloat(toInput.value)],
19
+ step: parseFloat(slider.getAttribute("data-step")),
20
+ connect: true,
21
+ format: wNumb({
22
+ decimals: parseFloat(slider.getAttribute("data-decimals")),
23
+ }),
24
+ range: {
25
+ min: parseFloat(slider.getAttribute("data-min")),
26
+ max: parseFloat(slider.getAttribute("data-max")),
27
+ },
28
+ });
29
+
30
+ /*************************************************************
31
+ * Update slider when input values change
32
+ *************************************************************/
33
+ fromInput.addEventListener("keyup", function () {
34
+ clearTimeout(this._sliderUpdateTimeout);
35
+ this._sliderUpdateTimeout = setTimeout(() => {
36
+ slider.noUiSlider.set([
37
+ parseFloat(this.value),
38
+ parseFloat(toInput.value),
39
+ ]);
40
+ }, 500);
41
+ });
42
+
43
+ toInput.addEventListener("keyup", function () {
44
+ clearTimeout(this._sliderUpdateTimeout);
45
+ this._sliderUpdateTimeout = setTimeout(() => {
46
+ slider.noUiSlider.set([
47
+ parseFloat(fromInput.value),
48
+ parseFloat(this.value),
49
+ ]);
50
+ }, 500);
51
+ });
27
52
 
28
- parent.querySelectorAll('.admin-numeric-filter-slider-tooltip-from')[0].innerHTML = values[0];
29
- parent.querySelectorAll('.admin-numeric-filter-slider-tooltip-to')[0].innerHTML = values[1];
53
+ /*************************************************************
54
+ * Updated inputs when slider is moved
55
+ *************************************************************/
56
+ slider.noUiSlider.on("update", function (values, handle) {
57
+ const parent = this.target.closest(".admin-numeric-filter-wrapper");
58
+ const from = parent.querySelectorAll(
59
+ ".admin-numeric-filter-wrapper-group input"
60
+ )[0];
61
+ const to = parent.querySelectorAll(
62
+ ".admin-numeric-filter-wrapper-group input"
63
+ )[1];
30
64
 
31
- from.value = values[0];
32
- to.value = values[1];
33
- });
65
+ from.value = values[0];
66
+ to.value = values[1];
34
67
  });
68
+ });
35
69
  });
@@ -8,22 +8,13 @@
8
8
  </h3>
9
9
 
10
10
  {% if choice.min is not None and choice.max is not None and choice.step %}
11
- <div class="admin-numeric-filter-slider-tooltips">
12
- <span class="admin-numeric-filter-slider-tooltip-from border border-base-200 cursor-not-allowed flex grow flex-row items-center mr-auto rounded-default shadow-xs px-3 py-2 w-full dark:bg-base-900 dark:border-base-700 dark:text-font-default-dark">
13
- {{ choice.value_from }}
14
- </span>
15
11
 
16
- <span class="admin-numeric-filter-slider-tooltip-to border border-base-200 cursor-not-allowed flex grow flex-row items-center rounded-default shadow-xs px-3 py-2 w-full dark:bg-base-900 dark:border-base-700 dark:text-font-default-dark">
17
- {{ choice.value_to }}
18
- </span>
12
+ <div class="admin-numeric-filter-wrapper-group flex flex-row gap-4 mb-4">
13
+ {{ choice.form.as_p }}
19
14
  </div>
20
15
 
21
16
  <div class="admin-numeric-filter-slider" data-min="{{ choice.min|unlocalize }}" data-max="{{ choice.max|unlocalize }}" data-decimals="{{ choice.decimals }}" data-step="{{ choice.step|unlocalize }}">
22
17
  </div>
23
-
24
- <div class="admin-numeric-filter-wrapper-group hidden">
25
- {{ choice.form.as_p }}
26
- </div>
27
18
  {% else %}
28
19
  <div class="admin-numeric-filter-slider-error dark:text-font-default-dark">
29
20
  <p class="border border-base-300 border-dashed leading-[36px] h-[38px] rounded-default text-center dark:border-base-700">
unfold/fields.py CHANGED
@@ -1,8 +1,11 @@
1
+ from typing import Union
2
+
1
3
  from django.contrib.admin import helpers
2
4
  from django.contrib.admin.utils import lookup_field, quote
3
5
  from django.core.exceptions import ObjectDoesNotExist
4
6
  from django.db import models
5
7
  from django.db.models import (
8
+ FileField,
6
9
  ForeignObjectRel,
7
10
  ImageField,
8
11
  JSONField,
@@ -36,6 +39,30 @@ class UnfoldAdminReadonlyField(helpers.AdminReadonlyField):
36
39
 
37
40
  return format_html("<label{}>{}</label>", flatatt(attrs), capfirst(label))
38
41
 
42
+ @property
43
+ def url(self) -> Union[str, bool]:
44
+ field, obj, model_admin = (
45
+ self.field["field"],
46
+ self.form.instance,
47
+ self.model_admin,
48
+ )
49
+
50
+ try:
51
+ f, attr, value = lookup_field(field, obj, model_admin)
52
+ except (AttributeError, ValueError, ObjectDoesNotExist):
53
+ return False
54
+
55
+ if not self.is_file():
56
+ return False
57
+
58
+ if hasattr(obj, field):
59
+ field_value = getattr(obj, field)
60
+
61
+ if field_value and hasattr(field_value, "url"):
62
+ return field_value.url
63
+
64
+ return False
65
+
39
66
  def is_json(self) -> bool:
40
67
  field, obj, model_admin = (
41
68
  self.field["field"],
@@ -73,6 +100,20 @@ class UnfoldAdminReadonlyField(helpers.AdminReadonlyField):
73
100
 
74
101
  return isinstance(f, ImageField)
75
102
 
103
+ def is_file(self) -> bool:
104
+ field, obj, model_admin = (
105
+ self.field["field"],
106
+ self.form.instance,
107
+ self.model_admin,
108
+ )
109
+
110
+ try:
111
+ f, attr, value = lookup_field(field, obj, model_admin)
112
+ except (AttributeError, ValueError, ObjectDoesNotExist):
113
+ return False
114
+
115
+ return isinstance(f, (ImageField, FileField))
116
+
76
117
  def contents(self) -> str:
77
118
  contents = self._get_contents()
78
119
  contents = self._preprocess_field(contents)