js_tree_element_improvement #161
@ -65,24 +65,23 @@ class KonovaCode(models.Model):
|
|||||||
ret_val += ", " + self.parent.long_name
|
ret_val += ", " + self.parent.long_name
|
||||||
return ret_val
|
return ret_val
|
||||||
|
|
||||||
def add_children(self):
|
def add_children(self, order_by: str = "long_name"):
|
||||||
""" Adds all children (resurcively until leaf) as .children to the KonovaCode
|
""" Adds all children (resurcively until leaf) as .children to the KonovaCode
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
code (KonovaCode): The manipulated KonovaCode instance
|
code (KonovaCode): The manipulated KonovaCode instance
|
||||||
"""
|
"""
|
||||||
if self.is_leaf:
|
if self.is_leaf:
|
||||||
return None
|
return self
|
||||||
|
|
||||||
children = KonovaCode.objects.filter(
|
children = KonovaCode.objects.filter(
|
||||||
code_lists__in=self.code_lists.all(),
|
|
||||||
parent=self
|
parent=self
|
||||||
).order_by(
|
).order_by(
|
||||||
"long_name"
|
order_by
|
||||||
)
|
)
|
||||||
self.children = children
|
self.children = children
|
||||||
for child in children:
|
for child in children:
|
||||||
child.add_children()
|
child.add_children(order_by)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,7 +17,8 @@ from codelist.models import KonovaCode
|
|||||||
from codelist.settings import CODELIST_BIOTOPES_ID, CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_EXTRA_CODES_ID, \
|
from codelist.settings import CODELIST_BIOTOPES_ID, CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_EXTRA_CODES_ID, \
|
||||||
CODELIST_COMPENSATION_ACTION_DETAIL_ID
|
CODELIST_COMPENSATION_ACTION_DETAIL_ID
|
||||||
from compensation.models import CompensationDocument, EcoAccountDocument
|
from compensation.models import CompensationDocument, EcoAccountDocument
|
||||||
from intervention.inputs import CompensationActionTreeCheckboxSelectMultiple
|
from intervention.inputs import CompensationActionTreeCheckboxSelectMultiple, \
|
||||||
|
CompensationStateTreeRadioSelect
|
||||||
from konova.contexts import BaseContext
|
from konova.contexts import BaseContext
|
||||||
from konova.forms import BaseModalForm, NewDocumentModalForm, RemoveModalForm
|
from konova.forms import BaseModalForm, NewDocumentModalForm, RemoveModalForm
|
||||||
from konova.models import DeadlineType
|
from konova.models import DeadlineType
|
||||||
@ -156,22 +157,12 @@ class NewStateModalForm(BaseModalForm):
|
|||||||
What has been on this area before changes/compensations have been applied and what will be the result ('after')?
|
What has been on this area before changes/compensations have been applied and what will be the result ('after')?
|
||||||
|
|
||||||
"""
|
"""
|
||||||
biotope_type = forms.ModelChoiceField(
|
biotope_type = forms.ChoiceField(
|
||||||
label=_("Biotope Type"),
|
label=_("Biotope Type"),
|
||||||
label_suffix="",
|
label_suffix="",
|
||||||
required=True,
|
required=True,
|
||||||
help_text=_("Select the biotope type"),
|
help_text=_("Select the biotope type"),
|
||||||
queryset=KonovaCode.objects.filter(
|
widget=CompensationStateTreeRadioSelect(),
|
||||||
is_archived=False,
|
|
||||||
is_leaf=True,
|
|
||||||
code_lists__in=[CODELIST_BIOTOPES_ID],
|
|
||||||
),
|
|
||||||
widget=autocomplete.ModelSelect2(
|
|
||||||
url="codes-biotope-autocomplete",
|
|
||||||
attrs={
|
|
||||||
"data-placeholder": _("Biotope Type"),
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
biotope_extra = forms.ModelMultipleChoiceField(
|
biotope_extra = forms.ModelMultipleChoiceField(
|
||||||
label=_("Biotope additional type"),
|
label=_("Biotope additional type"),
|
||||||
@ -209,6 +200,16 @@ class NewStateModalForm(BaseModalForm):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.form_title = _("New state")
|
self.form_title = _("New state")
|
||||||
self.form_caption = _("Insert data for the new state")
|
self.form_caption = _("Insert data for the new state")
|
||||||
|
choices = KonovaCode.objects.filter(
|
||||||
|
code_lists__in=[CODELIST_BIOTOPES_ID],
|
||||||
|
is_archived=False,
|
||||||
|
is_leaf=True,
|
||||||
|
).values_list("id", flat=True)
|
||||||
|
choices = [
|
||||||
|
(choice, choice)
|
||||||
|
for choice in choices
|
||||||
|
]
|
||||||
|
self.fields["biotope_type"].choices = choices
|
||||||
|
|
||||||
def save(self, is_before_state: bool = False):
|
def save(self, is_before_state: bool = False):
|
||||||
state = self.instance.add_state(self, is_before_state)
|
state = self.instance.add_state(self, is_before_state)
|
||||||
@ -271,8 +272,9 @@ class EditCompensationStateModalForm(NewStateModalForm):
|
|||||||
self.state = kwargs.pop("state", None)
|
self.state = kwargs.pop("state", None)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.form_title = _("Edit state")
|
self.form_title = _("Edit state")
|
||||||
|
biotope_type_id = self.state.biotope_type.id if self.state.biotope_type else None
|
||||||
form_data = {
|
form_data = {
|
||||||
"biotope_type": self.state.biotope_type,
|
"biotope_type": biotope_type_id,
|
||||||
"biotope_extra": self.state.biotope_type_details.all(),
|
"biotope_extra": self.state.biotope_type_details.all(),
|
||||||
"surface": self.state.surface,
|
"surface": self.state.surface,
|
||||||
}
|
}
|
||||||
@ -280,7 +282,8 @@ class EditCompensationStateModalForm(NewStateModalForm):
|
|||||||
|
|
||||||
def save(self, is_before_state: bool = False):
|
def save(self, is_before_state: bool = False):
|
||||||
state = self.state
|
state = self.state
|
||||||
state.biotope_type = self.cleaned_data.get("biotope_type", None)
|
biotope_type_id = self.cleaned_data.get("biotope_type", None)
|
||||||
|
state.biotope_type = KonovaCode.objects.get(id=biotope_type_id)
|
||||||
state.biotope_type_details.set(self.cleaned_data.get("biotope_extra", []))
|
state.biotope_type_details.set(self.cleaned_data.get("biotope_extra", []))
|
||||||
state.surface = self.cleaned_data.get("surface", None)
|
state.surface = self.cleaned_data.get("surface", None)
|
||||||
state.save()
|
state.save()
|
||||||
|
@ -8,6 +8,8 @@ Created on: 16.11.21
|
|||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
|
||||||
|
from codelist.models import KonovaCode
|
||||||
from user.models import User, Team
|
from user.models import User, Team
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.db.models import QuerySet, Sum
|
from django.db.models import QuerySet, Sum
|
||||||
@ -142,8 +144,10 @@ class AbstractCompensation(BaseObject, GeoReferencedMixin):
|
|||||||
"""
|
"""
|
||||||
form_data = form.cleaned_data
|
form_data = form.cleaned_data
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
|
biotope_type_id = form_data["biotope_type"]
|
||||||
|
code = KonovaCode.objects.get(id=biotope_type_id)
|
||||||
state = CompensationState.objects.create(
|
state = CompensationState.objects.create(
|
||||||
biotope_type=form_data["biotope_type"],
|
biotope_type=code,
|
||||||
surface=form_data["surface"],
|
surface=form_data["surface"],
|
||||||
)
|
)
|
||||||
state_additional_types = form_data["biotope_extra"]
|
state_additional_types = form_data["biotope_extra"]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from codelist.models import KonovaCode
|
from codelist.models import KonovaCode
|
||||||
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID
|
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID
|
||||||
|
|
||||||
|
|
||||||
class DummyFilterInput(forms.HiddenInput):
|
class DummyFilterInput(forms.HiddenInput):
|
||||||
@ -38,7 +38,17 @@ class TreeCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
|
|||||||
""" Provides multiple selection of parent-child data
|
""" Provides multiple selection of parent-child data
|
||||||
|
|
||||||
"""
|
"""
|
||||||
template_name = "konova/widgets/checkbox-tree-select.html"
|
template_name = "konova/widgets/tree/checkbox/checkbox-tree-select.html"
|
||||||
|
|
||||||
|
class meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
|
class TreeRadioSelect(forms.RadioSelect):
|
||||||
|
""" Provides single selection of parent-child data
|
||||||
|
|
||||||
|
"""
|
||||||
|
template_name = "konova/widgets/tree/radio/radio-tree-select.html"
|
||||||
|
|
||||||
class meta:
|
class meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
@ -68,6 +78,30 @@ class KonovaCodeTreeCheckboxSelectMultiple(TreeCheckboxSelectMultiple):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class KonovaCodeTreeRadioSelect(TreeRadioSelect):
|
||||||
|
""" Provides single selection of KonovaCode
|
||||||
|
|
||||||
|
"""
|
||||||
|
filter = None
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
self.code_list = kwargs.pop("code_list", None)
|
||||||
|
self.filter = kwargs.pop("filter", {})
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_context(self, name, value, attrs):
|
||||||
|
context = super().get_context(name, value, attrs)
|
||||||
|
codes = KonovaCode.objects.filter(
|
||||||
|
**self.filter,
|
||||||
|
)
|
||||||
|
codes = [
|
||||||
|
parent_code.add_children()
|
||||||
|
for parent_code in codes
|
||||||
|
]
|
||||||
|
context["codes"] = codes
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
class CompensationActionTreeCheckboxSelectMultiple(KonovaCodeTreeCheckboxSelectMultiple):
|
class CompensationActionTreeCheckboxSelectMultiple(KonovaCodeTreeCheckboxSelectMultiple):
|
||||||
""" Provides multiple selection of CompensationActions
|
""" Provides multiple selection of CompensationActions
|
||||||
|
|
||||||
@ -79,4 +113,31 @@ class CompensationActionTreeCheckboxSelectMultiple(KonovaCodeTreeCheckboxSelectM
|
|||||||
self.filter = {
|
self.filter = {
|
||||||
"code_lists__in": [CODELIST_COMPENSATION_ACTION_ID],
|
"code_lists__in": [CODELIST_COMPENSATION_ACTION_ID],
|
||||||
"parent": None,
|
"parent": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CompensationStateTreeRadioSelect(KonovaCodeTreeRadioSelect):
|
||||||
|
""" Provides single selection of CompensationState
|
||||||
|
|
||||||
|
"""
|
||||||
|
filter = None
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.filter = {
|
||||||
|
"code_lists__in": [CODELIST_BIOTOPES_ID],
|
||||||
|
"parent": None,
|
||||||
|
"is_archived": False,
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_context(self, name, value, attrs):
|
||||||
|
context = super().get_context(name, value, attrs)
|
||||||
|
codes = KonovaCode.objects.filter(
|
||||||
|
**self.filter,
|
||||||
|
)
|
||||||
|
codes = [
|
||||||
|
parent_code.add_children("short_name")
|
||||||
|
for parent_code in codes
|
||||||
|
]
|
||||||
|
context["codes"] = codes
|
||||||
|
return context
|
@ -262,4 +262,13 @@ Similar to bootstraps 'shadow-lg'
|
|||||||
padding-left: 2em;
|
padding-left: 2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
.collapse-icn > i{
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
.collapsed .collapse-icn > i{
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
.tree-label.badge{
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
@ -2,18 +2,23 @@
|
|||||||
|
|
||||||
{% for code in codes %}
|
{% for code in codes %}
|
||||||
<div class="ml-4 tree-element">
|
<div class="ml-4 tree-element">
|
||||||
<label class="tree-label" role="{% if not code.is_leaf%}button{% endif %}" for="input_{{code.pk|unlocalize}}" id="{{code.pk|unlocalize}}" data-toggle="collapse" data-target="#children_{{code.pk|unlocalize}}" aria-expanded="true" aria-controls="children_{{code.pk|unlocalize}}">
|
<label class="tree-label collapsed" role="{% if not code.is_leaf%}button{% endif %}" for="input_{{code.pk|unlocalize}}" id="{{code.pk|unlocalize}}" data-toggle="collapse" data-target="#children_{{code.pk|unlocalize}}" aria-expanded="true" aria-controls="children_{{code.pk|unlocalize}}">
|
||||||
{% if code.is_leaf%}
|
{% if code.is_leaf%}
|
||||||
<input class="tree-input" id="input_{{code.pk|unlocalize}}" name="{{ widget.name }}" type="checkbox" value="{{code.pk|unlocalize}}" {% if code.pk|unlocalize in widget.value %}checked{% endif %}/>
|
<input class="tree-input" id="input_{{code.pk|unlocalize}}" name="{{ widget.name }}" type="checkbox" value="{{code.pk|unlocalize}}" {% if code.pk|unlocalize in widget.value %}checked{% endif %}/>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% fa5_icon 'angle-right' %}
|
<span class="collapse-icn">
|
||||||
|
{% fa5_icon 'angle-down' %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if code.short_name %}
|
||||||
|
({{code.short_name}})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{code.long_name}}
|
{{code.long_name}}
|
||||||
</label>
|
</label>
|
||||||
{% if not code.is_leaf %}
|
{% if not code.is_leaf %}
|
||||||
<div id="children_{{code.pk|unlocalize}}" data-toggle="collapse" class="collapse tree-element-children">
|
<div id="children_{{code.pk|unlocalize}}" data-toggle="collapse" class="collapse tree-element-children">
|
||||||
{% with code.children as codes %}
|
{% with code.children as codes %}
|
||||||
{% include 'konova/widgets/checkbox-tree-select-content.html' %}
|
{% include 'konova/widgets/tree/checkbox/checkbox-tree-select-content.html' %}
|
||||||
{% endwith %}
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
@ -5,7 +5,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="tree-root">
|
<div id="tree-root">
|
||||||
{% include 'konova/widgets/checkbox-tree-select-content.html' %}
|
{% include 'konova/widgets/tree/checkbox/checkbox-tree-select-content.html' %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -47,9 +47,12 @@
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
if(val.length > 0){
|
if(val.length > 0){
|
||||||
|
// Hide everything
|
||||||
allTreeElements.hide()
|
allTreeElements.hide()
|
||||||
|
// Now show again everything matching the query
|
||||||
allTreeElementsContain.show()
|
allTreeElementsContain.show()
|
||||||
}else{
|
}else{
|
||||||
|
// Show everything if no query exists
|
||||||
allTreeElements.show()
|
allTreeElements.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
{% load l10n fontawesome_5 %}
|
||||||
|
{% for code in codes %}
|
||||||
|
<div class="ml-4 tree-element">
|
||||||
|
<label class="tree-label collapsed" role="{% if not code.is_leaf%}button{% endif %}" for="input_{{code.pk|unlocalize}}" id="{{code.pk|unlocalize}}" data-toggle="collapse" data-target="#children_{{code.pk|unlocalize}}" aria-expanded="true" aria-controls="children_{{code.pk|unlocalize}}">
|
||||||
|
{% if code.is_leaf%}
|
||||||
|
<input class="tree-input" id="input_{{code.pk|unlocalize}}" name="{{ widget.name }}" type="radio" value="{{code.pk|unlocalize}}" {% if code.pk|unlocalize in widget.value %}checked{% endif %}/>
|
||||||
|
{% else %}
|
||||||
|
<span class="collapse-icn">
|
||||||
|
{% fa5_icon 'angle-down' %}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% if code.short_name %}
|
||||||
|
({{code.short_name}})
|
||||||
|
{% endif %}
|
||||||
|
{{code.long_name}}
|
||||||
|
</label>
|
||||||
|
{% if not code.is_leaf %}
|
||||||
|
<div id="children_{{code.pk|unlocalize}}" data-toggle="collapse" class="collapse tree-element-children">
|
||||||
|
{% with code.children as codes %}
|
||||||
|
{% include 'konova/widgets/tree/radio/radio-tree-select-content.html' %}
|
||||||
|
{% endwith %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
@ -0,0 +1,62 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<div class="ml-4 mb-4">
|
||||||
|
<input id="tree-search-input" class="form-control" type="text" placeholder="{% trans 'Search' %}"/>
|
||||||
|
</div>
|
||||||
|
<div id="tree-root">
|
||||||
|
{% include 'konova/widgets/tree/radio/radio-tree-select-content.html' %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function toggleSelectedCssClass(element){
|
||||||
|
element = $(element);
|
||||||
|
var cssClass = "badge rlp-r"
|
||||||
|
|
||||||
|
// Find all already tagged input elements and reset them to be untagged
|
||||||
|
var allTaggedInputs = $("#tree-root").find(".badge.rlp-r")
|
||||||
|
allTaggedInputs.removeClass(cssClass)
|
||||||
|
|
||||||
|
// Find all parents of selected element
|
||||||
|
var parentElements = element.parents(".tree-element-children")
|
||||||
|
|
||||||
|
// Tag parents of element
|
||||||
|
var parentLabels = parentElements.siblings(".tree-label");
|
||||||
|
parentLabels.addClass(cssClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeHandler(event){
|
||||||
|
toggleSelectedCssClass(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchInputHandler(event){
|
||||||
|
var elem = $(this);
|
||||||
|
var val = elem.val()
|
||||||
|
var allTreeElements = $(".tree-element")
|
||||||
|
var allTreeElementsContain = $(".tree-element").filter(function(){
|
||||||
|
var reg = new RegExp(val, "i");
|
||||||
|
return reg.test($(this).text());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if(val.length > 0){
|
||||||
|
// Hide everything
|
||||||
|
allTreeElements.hide()
|
||||||
|
// Now show again everything matching the query
|
||||||
|
allTreeElementsContain.show()
|
||||||
|
}else{
|
||||||
|
// Show everything if no query exists
|
||||||
|
allTreeElements.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add event listener on search input
|
||||||
|
$("#tree-search-input").keyup(searchInputHandler)
|
||||||
|
|
||||||
|
// Add event listener on changed checkboxes
|
||||||
|
$(".tree-input").change(changeHandler);
|
||||||
|
|
||||||
|
// initialize all pre-checked checkboxes (e.g. on an edit form)
|
||||||
|
var preCheckedElements = $(".tree-input:checked");
|
||||||
|
preCheckedElements.each(function (index, element){
|
||||||
|
toggleSelectedCssClass(element);
|
||||||
|
})
|
||||||
|
</script>
|
Loading…
Reference in New Issue
Block a user