from combo.apps.dataviz
This commit is contained in:
parent
2b824e5b5a
commit
39dbdabcd3
|
@ -5,6 +5,7 @@
|
||||||
/gadjo.egg-info
|
/gadjo.egg-info
|
||||||
/gadjo/locale/fr/LC_MESSAGES/django.mo
|
/gadjo/locale/fr/LC_MESSAGES/django.mo
|
||||||
/gadjo/static/css/gadjo.css
|
/gadjo/static/css/gadjo.css
|
||||||
|
/gadjo/static/css/gadjo.multiselectwidget.css
|
||||||
/gadjo/static/css/icons
|
/gadjo/static/css/icons
|
||||||
node_modules
|
node_modules
|
||||||
MANIFEST
|
MANIFEST
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import django
|
||||||
|
from django import forms
|
||||||
|
|
||||||
|
|
||||||
|
class MultiSelectWidget(forms.MultiWidget):
|
||||||
|
template_name = 'gadjo/widgets/multiselectwidget.html'
|
||||||
|
|
||||||
|
class Media:
|
||||||
|
js = ('js/gadjo.multiselectwidget.js',)
|
||||||
|
css = {'all': ('css/gadjo.multiselectwidget.css',)}
|
||||||
|
|
||||||
|
def __init__(self, attrs=None):
|
||||||
|
self.attrs = attrs
|
||||||
|
widgets = [forms.Select(attrs=attrs)]
|
||||||
|
super().__init__(widgets, attrs)
|
||||||
|
|
||||||
|
def get_context(self, name, value, attrs):
|
||||||
|
if not isinstance(value, list):
|
||||||
|
value = [value]
|
||||||
|
|
||||||
|
self.widgets = []
|
||||||
|
for _ in range(max(len(value), 1)):
|
||||||
|
self.widgets.append(forms.Select(attrs=self.attrs, choices=self.choices))
|
||||||
|
|
||||||
|
# all subwidgets must have the same name
|
||||||
|
if django.VERSION >= (3, 1):
|
||||||
|
self.widgets_names = [''] * len(self.widgets)
|
||||||
|
return super().get_context(name, value, attrs)
|
||||||
|
else:
|
||||||
|
context = super().get_context(name, value, attrs)
|
||||||
|
subwidgets = context['widget']['subwidgets']
|
||||||
|
for widget in subwidgets:
|
||||||
|
widget['name'] = widget['name'].rsplit('_', 1)[0]
|
||||||
|
return context
|
||||||
|
|
||||||
|
def decompress(self, value):
|
||||||
|
return value or []
|
||||||
|
|
||||||
|
def value_from_datadict(self, data, files, name):
|
||||||
|
values = [x for x in data.getlist(name) if x]
|
||||||
|
|
||||||
|
# remove duplicates while keeping order
|
||||||
|
return list(dict.fromkeys(values))
|
||||||
|
|
||||||
|
def id_for_label(self, id_):
|
||||||
|
return id_
|
|
@ -0,0 +1,35 @@
|
||||||
|
.gadjo-multi-select-widget {
|
||||||
|
&--field {
|
||||||
|
margin-bottom: 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--select-button-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--field {
|
||||||
|
select {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-top: auto;
|
||||||
|
margin-bottom: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:first-of-type .gadjo-multi-select-widget--button-remove {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--button-add::before {
|
||||||
|
content: "\f067"; /* plus */
|
||||||
|
font-family: FontAwesome;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--button-remove::before {
|
||||||
|
content: "\f068"; /* minus */
|
||||||
|
font-family: FontAwesome;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
const multiSelectWidget = (function () {
|
||||||
|
const addRow = function () {
|
||||||
|
const widget = this.closest('.gadjo-multi-select-widget')
|
||||||
|
event.preventDefault()
|
||||||
|
|
||||||
|
/* get last row node */
|
||||||
|
const rows = widget.querySelectorAll('.gadjo-multi-select-widget--field')
|
||||||
|
const lastRow = rows[rows.length - 1]
|
||||||
|
|
||||||
|
/* clone the row */
|
||||||
|
const newRow = lastRow.cloneNode(true)
|
||||||
|
|
||||||
|
/* set new label and ids */
|
||||||
|
const rowLabel = widget.dataset.rowLabel
|
||||||
|
const newLabel = rowLabel + ' ' + rows.length
|
||||||
|
newRow.querySelector('label').textContent = newLabel
|
||||||
|
|
||||||
|
const rowId = widget.dataset.rowId
|
||||||
|
const newId = rowId + '_' + rows.length
|
||||||
|
newRow.querySelector('label').setAttribute('for', newId)
|
||||||
|
newRow.querySelector('select').setAttribute('id', newId)
|
||||||
|
|
||||||
|
/* add new row after the last row */
|
||||||
|
lastRow.parentNode.insertBefore(newRow, lastRow.nextSibling)
|
||||||
|
|
||||||
|
const removeButton = newRow.querySelector('.gadjo-multi-select-widget--button-remove')
|
||||||
|
removeButton.addEventListener('click', removeRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
const removeRow = function (event) {
|
||||||
|
event.preventDefault()
|
||||||
|
const field = this.closest('.content')
|
||||||
|
let row = this.closest('.gadjo-multi-select-widget--field')
|
||||||
|
row.remove()
|
||||||
|
field.dispatchEvent(new Event('change'))
|
||||||
|
}
|
||||||
|
|
||||||
|
const init = function (container) {
|
||||||
|
const widgets = container.querySelectorAll('.gadjo-multi-select-widget')
|
||||||
|
if (!widgets.length) return
|
||||||
|
|
||||||
|
widgets.forEach(function (widget) {
|
||||||
|
const deletBtn = widget.querySelector('.gadjo-multi-select-widget--button-remove')
|
||||||
|
const addBtn = widget.querySelector('.gadjo-multi-select-widget--button-add')
|
||||||
|
|
||||||
|
addBtn.removeEventListener('click', addRow)
|
||||||
|
addBtn.addEventListener('click', addRow)
|
||||||
|
deletBtn.removeEventListener('click', removeRow)
|
||||||
|
deletBtn.addEventListener('click', removeRow)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
init,
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', () => multiSelectWidget.init(document))
|
|
@ -0,0 +1,17 @@
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<div class="gadjo-multi-select-widget" data-row-id="{{ widget.name }}" data-row-label="{% trans "Value" %}">
|
||||||
|
<div class="gadjo-multi-select-widget--fields" role="group" aria-labelledby="{{ widget.name }}_title">
|
||||||
|
{% for widget in widget.subwidgets %}
|
||||||
|
<div class="gadjo-multi-select-widget--field">
|
||||||
|
<label for="{{ widget.name }}_{{ forloop.counter }}" class="sr-only">{% trans "Value" %} {{ forloop.counter }}</label>
|
||||||
|
<div class="gadjo-multi-select-widget--select-button-container">
|
||||||
|
{% include widget.template_name %}
|
||||||
|
<button type="button" name="{{ widget.name }}$remove_element" class="gadjo-multi-select-widget--button-remove" title="{% trans "Remove" %}" aria-label="{% trans "Remove value" %} {{ forloop.counter }}"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="button" name="{{ widget.name }}$add_element" class="gadjo-multi-select-widget--button-add" title="{% trans "Add" %}" aria-label="{% trans "Add" %}"></button>
|
||||||
|
</div>
|
Loading…
Reference in New Issue