from combo.apps.dataviz
This commit is contained in:
parent
2b824e5b5a
commit
39dbdabcd3
|
@ -5,6 +5,7 @@
|
|||
/gadjo.egg-info
|
||||
/gadjo/locale/fr/LC_MESSAGES/django.mo
|
||||
/gadjo/static/css/gadjo.css
|
||||
/gadjo/static/css/gadjo.multiselectwidget.css
|
||||
/gadjo/static/css/icons
|
||||
node_modules
|
||||
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