Skip to content

Commit

Permalink
material dropdowns work!
Browse files Browse the repository at this point in the history
  • Loading branch information
ed-p-may committed Dec 17, 2024
1 parent c556e1a commit b12c43b
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 102 deletions.
5 changes: 5 additions & 0 deletions static/css/select2.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@
border-radius: 3px !important;
border: 1px solid #939799 !important;
height: 100% !important;
}

.django-select2 {
/* Hide the default select. This may be a bug in Select2? */
display: none;
}
12 changes: 0 additions & 12 deletions webportal/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,3 @@ class MaterialSearchForm(forms.Form):
widget=Select2Widget(),
label="",
)

def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request", None)
super().__init__(*args, **kwargs)
if self.request:
self.fields["material"].queryset = Material.objects.filter(
user=self.request.user
)
if prefix := kwargs.get("prefix", None):
self.prefix = prefix
if auto_id := kwargs.get("auto_id", None):
self.auto_id = auto_id
15 changes: 9 additions & 6 deletions webportal/templates/webportal/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,26 @@

</div>

<script>
// Function to initialize Select2 (dropdowns with search)
<script>
function initializeSelect2() {
console.log('Select2 initialized');
$('.django-select2').select2();
$('.django-select2').select2().on('change', function () {
const form = $(this).closest('form')[0];
htmx.trigger(form, 'submit');
});
}

// Initialize Select2 on page load
document.addEventListener('DOMContentLoaded', function () {
console.log('Select2 style applied on page load');
initializeSelect2();
});

// Re-initialize Select2 after HTMX content swap
// This is necessary because HTMX replaces the content of the page
// without reloading the page, so the Select2 elements need to be
// re-initialized after the content is swapped.
document.body.addEventListener('htmx:afterSwap', function (event) {
console.log('Select2 style applied on HTMX swap');
initializeSelect2();
});
</script>
Expand Down
120 changes: 57 additions & 63 deletions webportal/templates/webportal/partials/assemblies/assembly.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
hx-post="{% url 'update-assembly-name' assembly.id %}"
hx-target="#assembly-name"
hx-swap="outerHTML"
hx-trigger="keyup delay:500ms"
hx-trigger="submit, focusout"
class="flex flex-1"
>
<input
Expand All @@ -28,95 +28,89 @@

{% block assembly-detail-view %}
<div id="assembly-detail-view" class="flex flex-col">

<div id="assembly-headers" class="flex flex-1 flex-row items-center">
<div class="justify-center text-center text-xs me-4" style="min-width:25px;">-</div>
<div class="justify-center text-center text-xs" style="max-width:10ch;">Thickness [M]</div>
<div class="flex flex-1 justify-center text-center text-xs">Layer Material</div>
</div>

<div id="assembly-cells">
<div id="assembly-layers">
{% for layer_view in layer_views %}

{% block layer %}
<div class="layer" id="layer-{{ layer_view.layer.pk }}">
<div class="flex flex-row items-center cell py-2" id="cell-{{ cell.pk }}">

<a
id="delete-layer-{{ assembly.pk }}"
hx-delete="{% url 'delete-layer' assembly_pk=assembly.pk layer_pk=layer_view.layer.pk %}"
hx-target="#assembly"
hx-swap="outerHTML"
hx-confirm="Delete?"
class="cursor-pointer me-2"
style="min-width:25px;">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="size-6 me-1">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
</svg>
</a>
<div class="layer flex flex-row items-center py-2" id="layer-{{ layer_view.layer.pk }}">
<a
id="delete-layer-{{ assembly.pk }}"
hx-delete="{% url 'delete-layer' assembly_pk=assembly.pk layer_pk=layer_view.layer.pk %}"
hx-target="#assembly"
hx-swap="outerHTML"
hx-confirm="Delete?"
class="cursor-pointer me-2"
style="min-width:25px;">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none" viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="size-6 me-1">
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
</svg>
</a>

<form
id="layer-thickness-form"
hx-post="{% url 'update-layer-thickness' assembly.id layer_view.layer.pk %}"
hx-target="#layer-thickness-{{ layer_view.layer.pk }}"
hx-swap="innerHTML"
hx-trigger="keyup delay:500ms"
class="me-1">
<input
id="layer-thickness-{{ layer_view.layer.pk }}"
type="text"
name="thickness"
class="text-black"
value={{ layer_view.layer.thickness }}
style="border: 1px solid #939799; padding: 8px; border-radius: 3px; background: var(--cell-color); max-width:10ch;"
onfocus="this.style.borderColor='#007bff'; this.style.boxShadow='0 0 5px rgba(0, 123, 255, 0.5)'; this.style.outline='none'; this.style.background='white'; this.style.color='black';"
onblur="this.style.borderColor='#ccc'; this.style.boxShadow='none'; this.style.background='var(--cell-color)';"
/>
</form>

<div class="layer-materials">
{% for segment, form in layer_view.segments_and_forms %}
<form
id="layer-material-form"
hx-post="{% url 'update-layer-material' assembly.id layer_view.layer.pk %}"
hx-target="#select2-id_form_{{ layer_view.layer.pk }}-material-container"
hx-swap="innerHTML"
hx-trigger="submit"
method="post"
name="material"
>
{{ form }}
</form>
{% endfor %}
</div>
<form
id="layer-thickness-form"
hx-post="{% url 'update-layer-thickness' assembly.id layer_view.layer.pk %}"
hx-target="#layer-thickness-{{ layer_view.layer.pk }}"
hx-swap="innerHTML"
hx-trigger="submit, focusout"
{% comment %} hx-trigger="keyup delay:500ms" {% endcomment %}
class="me-1">
<input
id="layer-thickness-{{ layer_view.layer.pk }}"
type="text"
name="thickness"
class="text-black"
value={{ layer_view.layer.thickness }}
style="border: 1px solid #939799; padding: 8px; border-radius: 3px; background: var(--cell-color); max-width:10ch;"
onfocus="this.style.borderColor='#007bff'; this.style.boxShadow='0 0 5px rgba(0, 123, 255, 0.5)'; this.style.outline='none'; this.style.background='white'; this.style.color='black';"
onblur="this.style.borderColor='#ccc'; this.style.boxShadow='none'; this.style.background='var(--cell-color)';"
/>
</form>

<div class="layer-segments">
{% for segment, form in layer_view.segments_and_forms %}
<form
hx-post="{% url 'update-layer-material' assembly.id layer_view.layer.pk %}"
hx-target="find [role='textbox']"
>
{{ form }}
</form>
{% endfor %}
</div>

</div>
{% endblock %}

{% endfor %}
</div>

<div id="grid-control-buttons" class="mt-10">
<button class="btn" hx-post="{% url 'add-layer' assembly.pk %}" hx-target="#assembly-cells" hx-swap="beforeend">Add New Layer +</button>
<button class="btn" hx-post="{% url 'add-layer' assembly.pk %}" hx-target="#assembly-layers" hx-swap="beforeend">Add New Layer +</button>
</div>

</div>
{% endblock %}

<script>
{% comment %} <script>
document.addEventListener('DOMContentLoaded', function () {
$('.django-select2').select2().on('change', function () {
this.closest('form').dispatchEvent(new Event('submit', { bubbles: true }));
});
});
</script>
</script> {% endcomment %}

{% endif %}
</div>
51 changes: 30 additions & 21 deletions webportal/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ class UnitSystem(Enum):
IP = "IP"


class LayerView:
"""A helper class to manage the Layer and its segments/forms in the Assembly view."""

def __init__(self, layer: Layer):
self.layer = layer
self.segments = layer.get_ordered_segments()
self.forms = [
MaterialSearchForm(
prefix=f"form_{segment.pk}",
initial={"material": segment.material.pk if segment.material else None},
)
for segment in self.segments
]

@property
def segments_and_forms(self):
return zip(self.segments, self.forms)


@require_POST
def set_unit_system(request: WSGIRequest) -> HttpResponse:
if request.POST.get("unit-system", None):
Expand Down Expand Up @@ -236,19 +255,6 @@ def assemblies_page(request: WSGIRequest) -> HttpResponse:
return render(request, "webportal/assemblies.html", context)


class LayerView:
def __init__(self, layer: Layer):
self.layer = layer
self.segments = layer.get_ordered_segments()
self.forms = [
MaterialSearchForm(prefix=f"form_{segment.pk}") for segment in self.segments
]

@property
def segments_and_forms(self):
return zip(self.segments, self.forms)


@login_required
def assembly(request: WSGIRequest, pk: int | None) -> HttpResponse:
"""The Assembly view with the sidebar.
Expand All @@ -257,7 +263,7 @@ def assembly(request: WSGIRequest, pk: int | None) -> HttpResponse:
"""

print(f">> assembly/{pk}")
# -------------------------------------------------------------------------
# -----------------------------------------------------------------------------------
# -- Detail-View
this_assembly = get_object_or_404(Assembly, pk=pk)
layers: list[Layer] = this_assembly.get_ordered_layers()
Expand All @@ -269,11 +275,11 @@ def assembly(request: WSGIRequest, pk: int | None) -> HttpResponse:
"webportal/partials/assemblies/assembly.html",
context={
"assembly": this_assembly,
"layer_views": [LayerView(layer) for layer in layers],
"layer_views": (LayerView(layer) for layer in layers),
},
)

# -------------------------------------------------------------------------
# -----------------------------------------------------------------------------------
# -- Sidebar
sidebar_html = render_block_to_string(
"webportal/partials/assemblies/sidebar.html",
Expand Down Expand Up @@ -383,13 +389,16 @@ def update_layer_material(
request: WSGIRequest, assembly_pk: int, layer_pk: int
) -> HttpResponse:
print(f">> {assembly_pk}/update_layer_material/{layer_pk}")

layer = get_object_or_404(Layer, id=layer_pk)
print(">> Layer:", layer)
if request.method == "POST":
# Select2 will return something like 'form_2-material' as the key
if mat_id := request.POST.get(f"segment_{layer.pk}-material", None):
new_material = Material.objects.get(id=mat_id)
for segment in layer.segments.all():
for segment in layer.segments.all():
print(">> Segment:", segment)
# Select2 will return something like 'form_2-material' as the key
if mat_id := request.POST.get(f"form_{segment.pk}-material", None):
new_material = Material.objects.get(id=mat_id)
segment.material = new_material
segment.save()
return HttpResponse(new_material.name)
return HttpResponse(new_material.name)
return HttpResponse()

0 comments on commit b12c43b

Please sign in to comment.