Merge pull request 'js_tree_element_improvement' (#161) from js_tree_element_improvement into master

Reviewed-on: SGD-Nord/konova#161
pull/162/head
mpeltriaux 2 years ago
commit 21d1fabeec

@ -65,24 +65,23 @@ class KonovaCode(models.Model):
ret_val += ", " + self.parent.long_name
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
Returns:
code (KonovaCode): The manipulated KonovaCode instance
"""
if self.is_leaf:
return None
return self
children = KonovaCode.objects.filter(
code_lists__in=self.code_lists.all(),
parent=self
).order_by(
"long_name"
order_by
)
self.children = children
for child in children:
child.add_children()
child.add_children(order_by)
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, \
CODELIST_COMPENSATION_ACTION_DETAIL_ID
from compensation.models import CompensationDocument, EcoAccountDocument
from intervention.inputs import CompensationActionTreeCheckboxSelectMultiple
from intervention.inputs import CompensationActionTreeCheckboxSelectMultiple, \
CompensationStateTreeRadioSelect
from konova.contexts import BaseContext
from konova.forms import BaseModalForm, NewDocumentModalForm, RemoveModalForm
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')?
"""
biotope_type = forms.ModelChoiceField(
biotope_type = forms.ChoiceField(
label=_("Biotope Type"),
label_suffix="",
required=True,
help_text=_("Select the biotope type"),
queryset=KonovaCode.objects.filter(
is_archived=False,
is_leaf=True,
code_lists__in=[CODELIST_BIOTOPES_ID],
),
widget=autocomplete.ModelSelect2(
url="codes-biotope-autocomplete",
attrs={
"data-placeholder": _("Biotope Type"),
}
),
widget=CompensationStateTreeRadioSelect(),
)
biotope_extra = forms.ModelMultipleChoiceField(
label=_("Biotope additional type"),
@ -209,6 +200,16 @@ class NewStateModalForm(BaseModalForm):
super().__init__(*args, **kwargs)
self.form_title = _("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):
state = self.instance.add_state(self, is_before_state)
@ -271,8 +272,9 @@ class EditCompensationStateModalForm(NewStateModalForm):
self.state = kwargs.pop("state", None)
super().__init__(*args, **kwargs)
self.form_title = _("Edit state")
biotope_type_id = self.state.biotope_type.id if self.state.biotope_type else None
form_data = {
"biotope_type": self.state.biotope_type,
"biotope_type": biotope_type_id,
"biotope_extra": self.state.biotope_type_details.all(),
"surface": self.state.surface,
}
@ -280,7 +282,8 @@ class EditCompensationStateModalForm(NewStateModalForm):
def save(self, is_before_state: bool = False):
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.surface = self.cleaned_data.get("surface", None)
state.save()

@ -8,6 +8,8 @@ Created on: 16.11.21
import shutil
from django.contrib import messages
from codelist.models import KonovaCode
from user.models import User, Team
from django.db import models, transaction
from django.db.models import QuerySet, Sum
@ -142,8 +144,10 @@ class AbstractCompensation(BaseObject, GeoReferencedMixin):
"""
form_data = form.cleaned_data
with transaction.atomic():
biotope_type_id = form_data["biotope_type"]
code = KonovaCode.objects.get(id=biotope_type_id)
state = CompensationState.objects.create(
biotope_type=form_data["biotope_type"],
biotope_type=code,
surface=form_data["surface"],
)
state_additional_types = form_data["biotope_extra"]

@ -1,6 +1,6 @@
from django import forms
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):
@ -38,7 +38,17 @@ class TreeCheckboxSelectMultiple(forms.CheckboxSelectMultiple):
""" 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:
abstract = True
@ -68,6 +78,30 @@ class KonovaCodeTreeCheckboxSelectMultiple(TreeCheckboxSelectMultiple):
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):
""" Provides multiple selection of CompensationActions
@ -80,3 +114,30 @@ class CompensationActionTreeCheckboxSelectMultiple(KonovaCodeTreeCheckboxSelectM
"code_lists__in": [CODELIST_COMPENSATION_ACTION_ID],
"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

@ -263,3 +263,12 @@ Similar to bootstraps 'shadow-lg'
}
*/
.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 %}
<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%}
<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 %}
{% fa5_icon 'angle-right' %}
<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/checkbox-tree-select-content.html' %}
{% include 'konova/widgets/tree/checkbox/checkbox-tree-select-content.html' %}
{% endwith %}
</div>
{% endif %}

@ -5,7 +5,7 @@
</div>
<div id="tree-root">
{% include 'konova/widgets/checkbox-tree-select-content.html' %}
{% include 'konova/widgets/tree/checkbox/checkbox-tree-select-content.html' %}
</div>
<script>
@ -47,9 +47,12 @@
}
);
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()
}
}

@ -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…
Cancel
Save