[UPDT] HORILLA WIDGETS: Multiple Widget not working in same form issue

This commit is contained in:
Horilla
2024-07-17 15:48:28 +05:30
parent bbfb0a275f
commit b198c06564
5 changed files with 280 additions and 262 deletions

View File

@@ -1,213 +1,215 @@
{% load i18n %}
<style>
.oh-modal__close-custom {
border: none;
background: none;
font-size: 1.5rem;
opacity: 0.7;
position: absolute;
top: 25px;
right: 15px;
cursor: pointer;
}
.tag-badge {
box-sizing: border-box;
display: inline-block;
/* background-color: orangered; */
color: black;
<div id="{{section_id}}">
{% load i18n %}
<style>
.oh-modal__close-custom {
border: none;
background: none;
font-size: 1.5rem;
opacity: 0.7;
position: absolute;
top: 25px;
right: 15px;
cursor: pointer;
}
.tag-badge {
box-sizing: border-box;
display: inline-block;
/* background-color: orangered; */
color: black;
border-radius: 3rem;
text-align: center;
border-radius: 3rem;
text-align: center;
font-size: 1.6rem;
font-weight: 400;
padding: 0.05rem 0.8rem 0.1rem;
line-height: inherit;
padding: 7px;
padding-right: 10px;
margin-bottom: 5px;
border: solid orangered 2px;
cursor: pointer;
}
.tag-badge--primary {
background-color: orangered;
color: white;
}
.oh-profile__avatar-limit-height {
height: 30px !important;
}
.oh-profile_name_custom {
font-size: 13px;
padding-left: 4px;
}
.oh-profile__image_custm {
width: 26px;
height: 26px;
}
.badge-container {
height: 30vh;
overflow: auto;
}
.tag-badge--outline {
background: white;
border: solid orangered 2px;
color: black;
}
.oh-sticky-table__th--custom {
padding-left: 10px !important;
}
.oh-sticky-table__tr--selected {
background: #ff450017 !important;
}
font-size: 1.6rem;
font-weight: 400;
padding: 0.05rem 0.8rem 0.1rem;
line-height: inherit;
padding: 7px;
padding-right: 10px;
margin-bottom: 5px;
border: solid orangered 2px;
cursor: pointer;
}
.tag-badge--primary {
background-color: orangered;
color: white;
}
.oh-profile__avatar-limit-height {
height: 30px !important;
}
.oh-profile_name_custom {
font-size: 13px;
padding-left: 4px;
}
.oh-profile__image_custm {
width: 26px;
height: 26px;
}
.badge-container {
height: 30vh;
overflow: auto;
}
.tag-badge--outline {
background: white;
border: solid orangered 2px;
color: black;
}
.oh-sticky-table__th--custom {
padding-left: 10px !important;
}
.oh-sticky-table__tr--selected {
background: #ff450017 !important;
}
.avatars {
display: flex;
padding: 8px 10px 8px 10px;
}
.avatars__item {
background-color: #596376;
border: 2px solid white;
border-radius: 100%;
color: #ffffff;
display: block;
font-family: sans-serif;
font-size: 12px;
font-weight: 100;
height: 26px;
width: 26px;
line-height: 17px;
text-align: center;
transition: margin 0.1s ease-in-out;
overflow: hidden;
margin-left: -10px;
}
.avatars__item:first-child {
z-index: 5;
}
.avatars__item:nth-child(2) {
z-index: 4;
}
.avatars__item:nth-child(3) {
z-index: 3;
}
.avatars__item:nth-child(4) {
z-index: 2;
}
.avatars__item:nth-child(5) {
z-index: 1;
}
.avatars__item:last-child {
z-index: 0;
}
.avatars__item img {
width: 100%;
}
.avatars:hover .avatars__item {
margin-right: 10px;
}
.select2{
width: 100% !important;
}
#slectContainer{{self.attrs.id}} .select2-container .select2-selection{
padding: 5px !important;
max-height: 70px !important;
overflow: hidden;
overflow-y: scroll;
}
.custom-scroll{
overflow-x: scroll
}
.custom-scroll::-webkit-scrollbar{
background-color: #cacaca;
height: 4px;
border-radius: 6px;
}
.custom-scroll::-webkit-scrollbar-thumb{
background-color: #888;
border-radius: 6px;
}
</style>
<div id="slectContainer{{self.attrs.id}}">
<select name="{{field_name}}" id="{{self.attrs.id}}" {% if required %}required{% endif %} class="w-100 oh-select oh-select2" multiple>
{% for instance in queryset %}
<option value="{{instance.id}}">{{instance}}</option>
{% endfor %}
</select>
</div>
<!-- custom scroll/ horizontal scroll section -->
<div class="d-flex justify-content-between custom-scroll">
<div class="avatars" id="avatarsContainer"></div>
</div>
<span
style="
cursor: pointer;
padding: 10px;
display: flex;
justify-content: right;
color: orangered;
"
>
<span
data-toggle="oh-modal-toggle"
data-target="#filterChoose"
title="Filter and Choose {{field.label}}"
style="
justify-content: right;
align-items: center;
.avatars {
display: flex;
width: 50px;
padding: 8px 10px 8px 10px;
}
.avatars__item {
background-color: #596376;
border: 2px solid white;
border-radius: 100%;
color: #ffffff;
display: block;
font-family: sans-serif;
font-size: 12px;
font-weight: 100;
height: 26px;
width: 26px;
line-height: 17px;
text-align: center;
transition: margin 0.1s ease-in-out;
overflow: hidden;
margin-left: -10px;
}
.avatars__item:first-child {
z-index: 5;
}
.avatars__item:nth-child(2) {
z-index: 4;
}
.avatars__item:nth-child(3) {
z-index: 3;
}
.avatars__item:nth-child(4) {
z-index: 2;
}
.avatars__item:nth-child(5) {
z-index: 1;
}
.avatars__item:last-child {
z-index: 0;
}
.avatars__item img {
width: 100%;
}
.avatars:hover .avatars__item {
margin-right: 10px;
}
.select2{
width: 100% !important;
}
#slectContainer{{self.attrs.id}} .select2-container .select2-selection{
padding: 5px !important;
max-height: 70px !important;
overflow: hidden;
overflow-y: scroll;
}
.custom-scroll{
overflow-x: scroll
}
.custom-scroll::-webkit-scrollbar{
background-color: #cacaca;
height: 4px;
border-radius: 6px;
}
.custom-scroll::-webkit-scrollbar-thumb{
background-color: #888;
border-radius: 6px;
}
</style>
<div id="slectContainer{{self.attrs.id}}">
<select name="{{field_name}}" id="{{self.attrs.id}}" {% if required %}required{% endif %} class="w-100 oh-select oh-select2" multiple>
{% for instance in queryset %}
<option value="{{instance.id}}">{{instance}}</option>
{% endfor %}
</select>
</div>
<!-- custom scroll/ horizontal scroll section -->
<div class="d-flex justify-content-between custom-scroll">
<div class="avatars" id="avatarsContainer"></div>
</div>
<span
style="
cursor: pointer;
padding: 10px;
display: flex;
justify-content: right;
color: orangered;
"
>
<ion-icon name="filter-circle"></ion-icon> {% trans "Filter" %}
</span>
</span>
<div
class="oh-modal"
id="filterChoose"
role="dialog"
aria-labelledby="filterChoose"
aria-hidden="true"
>
<div class="oh-modal__dialog">
<div class="oh-modal__dialog-header">
<button
type="button"
class="oh-modal__close-custom"
onclick="event.stopPropagation();event.preventDefault;$('#filterChoose').toggleClass('oh-modal--show');"
>
<ion-icon name="close-outline"></ion-icon>
</button>
</div>
<div
class="oh-modal__dialog-body"
id="filterChooseModalBody{{self.attrs.id}}"
<span
data-toggle="oh-modal-toggle"
data-target="#filterChoose{{section_id}}"
title="Filter and Choose {{field.label}}"
style="
justify-content: right;
align-items: center;
display: flex;
width: 50px;
"
>
<div class="oh-wrapper">
<!-- Nav -->
{% include "horilla_widgets/multiselect_components/nav.html" %}
<!-- Filter Tags -->
{% include "horilla_widgets/multiselect_components/filter_tags.html" %}
<!-- Sticky Table -->
{% include "horilla_widgets/multiselect_components/table.html" %}
<!-- Pagination -->
{% include "horilla_widgets/multiselect_components/pagination.html" %}
<div class="d-flex flex-row-reverse">
<a
class="oh-btn oh-btn--secondary oh-btn--shadow pr-3 pl-3"
onclick="event.stopPropagation();event.preventDefault;$('#filterChoose').toggleClass('oh-modal--show');"
>
{% trans "Add" %}
</a>
<ion-icon name="filter-circle"></ion-icon> {% trans "Filter" %}
</span>
</span>
<div
class="oh-modal"
id="filterChoose{{section_id}}"
role="dialog"
aria-labelledby="filterChoose{{section_id}}"
aria-hidden="true"
>
<div class="oh-modal__dialog">
<div class="oh-modal__dialog-header">
<button
type="button"
class="oh-modal__close-custom"
onclick="event.stopPropagation();event.preventDefault;$('#filterChoose{{section_id}}').toggleClass('oh-modal--show');"
>
<ion-icon name="close-outline"></ion-icon>
</button>
</div>
<div
class="oh-modal__dialog-body"
id="filterChooseModalBody{{self.attrs.id}}"
>
<div class="oh-wrapper">
<!-- Nav -->
{% include "horilla_widgets/multiselect_components/nav.html" %}
<!-- Filter Tags -->
{% include "horilla_widgets/multiselect_components/filter_tags.html" %}
<!-- Sticky Table -->
{% include "horilla_widgets/multiselect_components/table.html" %}
<!-- Pagination -->
{% include "horilla_widgets/multiselect_components/pagination.html" %}
<div class="d-flex flex-row-reverse">
<a
class="oh-btn oh-btn--secondary oh-btn--shadow pr-3 pl-3"
onclick="event.stopPropagation();event.preventDefault;$('#filterChoose{{section_id}}').removeClass('oh-modal--show');"
>
{% trans "Add" %}
</a>
</div>
</div>
</div>
</div>

View File

@@ -85,9 +85,9 @@
return modifiedJson;
}
$("#widgetFilterButton{{self.attrs.id}}").click(function (e) {
$("#{{section_id}} #widgetFilterButton{{self.attrs.id}}").click(function (e) {
e.preventDefault();
const formFields = $("#widgetFilterFormContainer{{self.attrs.id}}").find(
const formFields = $("#{{section_id}} #widgetFilterFormContainer{{self.attrs.id}}").find(
"[name]"
);
var formData = [];
@@ -103,25 +103,25 @@
data: formData,
success: function (response) {
let ids = response.ids;
$("#chooseTableHeaderParent .oh-sticky-table__tbody").hide();
$("#{{section_id}} #chooseTableHeaderParent .oh-sticky-table__tbody").hide();
$.each(ids, function (indexInArray, valueOfElement) {
$(
`#chooseTableHeaderParent .oh-sticky-table__tbody[data-instance-id=${valueOfElement}]`
`#{{section_id}} #chooseTableHeaderParent .oh-sticky-table__tbody[data-instance-id=${valueOfElement}]`
).show();
});
$(".visible-count").html(
$(".oh-sticky-table__tr--custom:visible .oh-sticky-table__sd")
$("#{{section_id}} .visible-count").html(
$("#{{section_id}} .oh-sticky-table__tr--custom:visible .oh-sticky-table__sd")
.length
);
var labeledTags = transformJson(formData);
var tagContainer = $("#filterTagContainer{{self.attrs.id}}");
var tagContainer = $("#{{section_id}} #filterTagContainer{{self.attrs.id}}");
tagContainer.html("");
$.each(labeledTags, function (indexInArray, valueOfElement) {
if (valueOfElement.value.length != 0) {
tagContainer.append(
$(`
<span class="oh-filter-tag" id="tag-{{self.attrs.id}}"
>${valueOfElement.name}<button class="oh-filter-tag__close" onclick="closeFilterTag(event, ${formData[indexInArray].name}, '#tag-{{self.attrs.id}}')">
>${valueOfElement.name}<button class="oh-filter-tag__close" onclick="closeFilterTag(event, ${formData[indexInArray].name}, '#{{section_id}} #tag-{{self.attrs.id}}')">
<ion-icon name="close-outline"></ion-icon></button
>
</span>`)
@@ -131,9 +131,9 @@
},
});
});
$("#widgetFilterFormContainer{{self.attrs.id}} [name=search]").keyup(
$("#{{section_id}} #widgetFilterFormContainer{{self.attrs.id}} [name=search]").keyup(
function (e) {
$("#widgetFilterButton{{self.attrs.id}}").click();
$("#{{section_id}} #widgetFilterButton{{self.attrs.id}}").click();
}
);
});
@@ -146,7 +146,7 @@
.find(`#select2-${$(fieldName).attr("id")}-container`)
.html("---------");
}
$("#widgetFilterButton{{self.attrs.id}}").click();
$("#{{section_id}} #widgetFilterButton{{self.attrs.id}}").click();
$(targetTag).remove();
}
</script>

View File

@@ -38,23 +38,23 @@
<script>
$(document).ready(function () {
function updateSelectedCount(){
let selectedCount = $(".tag-badge").not(".tag-badge--outline").length
$(".selected-count").html(selectedCount);
let selectedCount = $("#{{section_id}} .tag-badge").not(".tag-badge--outline").length
$("#{{section_id}} .selected-count").html(selectedCount);
}
$(".tag-badge").click(function (e) {
$("#{{section_id}} .tag-badge").click(function (e) {
e.preventDefault();
$(this).toggleClass("tag-badge--outline");
updateSelectedCount()
});
$("#selectSelected").click(function (e) {
$("#{{section_id}} #selectSelected").click(function (e) {
e.preventDefault();
$(".tag-badge").removeClass("tag-badge--outline");
$("#{{section_id}} .tag-badge").removeClass("tag-badge--outline");
updateSelectedCount()
});
$("#unselectSelected").click(function (e) {
$("#{{section_id}} #unselectSelected").click(function (e) {
e.preventDefault();
$(".tag-badge").addClass("tag-badge--outline");
$("#{{section_id}} .tag-badge").addClass("tag-badge--outline");
updateSelectedCount()
});
});

View File

@@ -61,15 +61,15 @@
<script>
let selectedIds = [];
$(document).ready(function () {
$("#{{self.attrs.id}}").select2({
$("#{{section_id}} #{{self.attrs.id}}").select2({
multiple: true,
});
$("#{{self.attrs.id}}")
$("#{{section_id}} #{{self.attrs.id}}")
.next()
.find(".select2-container")
.css("width", "100%");
$("#chooseTableHeader")
$("#{{section_id}} #chooseTableHeader")
.not("[type=checkbox]")
.click(function (e) {
e.preventDefault();
@@ -78,33 +78,33 @@
} else {
$(this).find("[type=checkbox]:first").prop("checked", true);
}
$("#choose-all-user").change();
$("#{{section_id}} #choose-all-user").change();
});
$("#selectAllUsers").click(function (e) {
$("#{{section_id}} #selectAllUsers").click(function (e) {
e.preventDefault();
$("#choose-all-user").prop("checked", true);
$("#choose-all-user").change();
$("#{{section_id}} #choose-all-user").prop("checked", true);
$("#{{section_id}} #choose-all-user").change();
});
$("#unselectAllUsers").click(function (e) {
$("#{{section_id}} #unselectAllUsers").click(function (e) {
e.preventDefault();
$("#choose-all-user").prop("checked", false);
$("#choose-all-user").change();
$("#{{section_id}} #choose-all-user").prop("checked", false);
$("#{{section_id}} #choose-all-user").change();
});
$("#choose-all-user").change(function (e) {
$("#{{section_id}} #choose-all-user").change(function (e) {
e.preventDefault();
if ($(this).is(":checked")) {
$(".all-choose-user-row:visible").prop("checked", true);
$(".oh-sticky-table__tr--custom:visible .oh-sticky-table__sd").addClass(
$("#{{section_id}} .all-choose-user-row:visible").prop("checked", true);
$("#{{section_id}} .oh-sticky-table__tr--custom:visible .oh-sticky-table__sd").addClass(
"oh-sticky-table__tr--selected"
);
} else {
$(".all-choose-user-row:visible").prop("checked", false);
$("#{{section_id}} .all-choose-user-row:visible").prop("checked", false);
$(
".oh-sticky-table__tr--custom:visible .oh-sticky-table__sd"
"#{{section_id}} .oh-sticky-table__tr--custom:visible .oh-sticky-table__sd"
).removeClass("oh-sticky-table__tr--selected");
}
});
$(".oh-sticky-table__tr--custom").click(function (e) {
$("#{{section_id}} .oh-sticky-table__tr--custom").click(function (e) {
var checkbox = $(this).find("[type=checkbox]");
// Toggle the checkbox's checked state
@@ -125,9 +125,9 @@
return !checked;
});
});
$("#filterChoose").click(function (e) {
$("#{{section_id}} #filterChoose{{section_id}}").click(function (e) {
e.preventDefault();
var selectedRows = $("#filterChoose div").find(
var selectedRows = $("#{{section_id}} #filterChoose{{section_id}} div").find(
".oh-sticky-table__tr--selected"
);
var ids = [];
@@ -139,44 +139,44 @@
instanceData.push({ id: id, label: label });
});
var selectedCount = selectedRows.length;
$(".selected-count").html(selectedCount);
$("#{{section_id}} .selected-count").html(selectedCount);
$("#{{self.attrs.id}}").val(ids);
$("#{{self.attrs.id}}").change();
$("#avatarsContainer").html("");
$("#{{section_id}} #{{self.attrs.id}}").val(ids);
$("#{{section_id}} #{{self.attrs.id}}").change();
$("#{{section_id}} #avatarsContainer").html("");
$.each(instanceData, function (indexInArray, valueOfElement) {
var imgUrl = $(
`.oh-sticky-table__tr.oh-sticky-table__tr--custom[data-instance-id=${valueOfElement.id}]`
`#{{section_id}} .oh-sticky-table__tr.oh-sticky-table__tr--custom[data-instance-id=${valueOfElement.id}]`
).attr("data-avatar");
$("#avatarsContainer").append(
$("#{{section_id}} #avatarsContainer").append(
$(
`<a href="#" class="avatars__item" title="${valueOfElement.label}"><img class="avatar" src="${imgUrl}" alt=""></a>`
)
);
});
});
$("#selectAllInstances").click(function (e) {
$("#{{section_id}} #selectAllInstances").click(function (e) {
e.preventDefault();
$("#choose-all-user").prop("checked", true);
$(".all-choose-user-row").prop("checked", true);
$(".oh-sticky-table__tr--custom .oh-sticky-table__sd").addClass(
$("#{{section_id}} #choose-all-user").prop("checked", true);
$("#{{section_id}} .all-choose-user-row").prop("checked", true);
$("#{{section_id}} .oh-sticky-table__tr--custom .oh-sticky-table__sd").addClass(
"oh-sticky-table__tr--selected"
);
$("#choose-all-user").change();
$("#{{section_id}} #choose-all-user").change();
});
$("#{{ self.attrs.id }}").change(function (e) {
$("#{{section_id}} #{{ self.attrs.id }}").change(function (e) {
e.preventDefault();
// Get all selected options
$("#avatarsContainer").html("");
$(".oh-sticky-table__tr--selected")
$("#{{section_id}} #avatarsContainer").html("");
$("#{{section_id}} .oh-sticky-table__tr--selected")
.find("[type=checkbox]")
.prop("checked", false);
$(".oh-sticky-table__tr--selected").removeClass(
$("#{{section_id}} .oh-sticky-table__tr--selected").removeClass(
"oh-sticky-table__tr--selected"
);
var selectedOptions = $(this).find(`:selected`);
$(".selected-count").html(selectedOptions.length);
$("#{{section_id}} .selected-count").html(selectedOptions.length);
// Loop through the selected options
selectedOptions.each(function (indexInArray, valueOfElement) {
@@ -184,28 +184,31 @@
var optionHtml = $(this).html();
// Append the selected option's HTML to the avatarsContainer
var imgUrl = $(
`.oh-sticky-table__tr.oh-sticky-table__tr--custom[data-instance-id=${$(
`#{{section_id}} .oh-sticky-table__tr.oh-sticky-table__tr--custom[data-instance-id=${$(
valueOfElement
).val()}]`
).attr("data-avatar");
$("#avatarsContainer").append(
$("#{{section_id}} #avatarsContainer").append(
$(
`<a href="#" class="avatars__item" title="${optionHtml}"><img class="avatar" src="${imgUrl}" alt=""></a>`
)
);
var optValue = $(valueOfElement).val();
var rowId = "#selectRow{{self.attrs.id}}" + optValue;
var rowId = "#{{section_id}} #selectRow{{self.attrs.id}}" + optValue;
$(rowId).addClass("oh-sticky-table__tr--selected");
$(rowId).find("[type=checkbox]").prop("checked", true);
});
});
{% if initial %}
$('#{{section_id}} #slectContainer{{self.attrs.id}}').find("[name={{field_name}}]").val({{initial|safe}}).change()
{% endif %}
});
$("#choose-all-user").click(function (e) {
$("#{{section_id}} #choose-all-user").click(function (e) {
setTimeout(() => {
$("#choose-all-user").closest(".oh-sticky-table__th--custom")[0].click()
$("#{{section_id}} #choose-all-user").closest(".oh-sticky-table__th--custom")[0].click()
}, 2);
});
$(".all-choose-user-row").click(function (e) {
$("#{{section_id}} .all-choose-user-row").click(function (e) {
e.preventDefault();
setTimeout(() => {
$(this).closest(".oh-sticky-table__tr--custom")[0].click()

View File

@@ -4,7 +4,7 @@ select_widgets.py
This module is used to write horilla form select widgets
"""
import datetime
import uuid
from django import forms
@@ -13,6 +13,14 @@ from horilla import horilla_middlewares
ALL_INSTANCES = {}
def get_short_uuid(length: int, prefix: str = "widget"):
"""
Short uuid generating method
"""
uuid_str = str(uuid.uuid4().hex)
return prefix + str(uuid_str[:length]).replace("-", "")
class HorillaMultiSelectWidget(forms.Widget):
"""
HorillaMultiSelectWidget
@@ -47,6 +55,9 @@ class HorillaMultiSelectWidget(forms.Widget):
field = self.choices.field
context["queryset"] = queryset
context["field_name"] = name
if self.instance and self.instance.pk:
initial = list(getattr(self.instance, name).values_list("id", flat=True))
context["initial"] = initial
context["field"] = field
context["self"] = self
context["filter_template_path"] = self.filter_template_path
@@ -55,6 +66,8 @@ class HorillaMultiSelectWidget(forms.Widget):
self.attrs["id"] = (
("id_" + name) if self.attrs.get("id") is None else self.attrs.get("id")
)
uid = get_short_uuid(5)
context["section_id"] = uid
context[self.filter_instance_contex_name] = self.filter_class
request = getattr(horilla_middlewares._thread_locals, "request", None)
ALL_INSTANCES[str(request.user.id)] = self