From a0758111737f036e36d62586e8e445da5b591cd0 Mon Sep 17 00:00:00 2001 From: "Adrian A. Baumann" Date: Sat, 1 Nov 2025 00:34:21 +0100 Subject: [PATCH] Collapsing and drag/drop implemented --- dokumente/admin.py | 12 +++--- static/admin/js/vorgabe_collapse.js | 67 ++++++++++++++++++++++------- 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/dokumente/admin.py b/dokumente/admin.py index 96cd74a..f03f9b5 100644 --- a/dokumente/admin.py +++ b/dokumente/admin.py @@ -97,15 +97,15 @@ class VorgabeForm(forms.ModelForm): model = Vorgabe fields = '__all__' -class VorgabeInline(SortableInlineAdminMixin, NestedStackedInline): # Changed to StackedInline for better box separation +class VorgabeInline(SortableInlineAdminMixin, NestedStackedInline): model = Vorgabe form = VorgabeForm extra = 0 - sortable_field_name = "order" # Add this - make sure your Vorgabe model has an 'order' field + sortable_field_name = "order" show_change_link = True inlines = [VorgabeKurztextInline, VorgabeLangtextInline, ChecklistenfragenInline] autocomplete_fields = ['stichworte','referenzen','relevanz'] - classes = ["collapse"] # Start collapsed for better overview + # Remove collapse class so Vorgaben show by default fieldsets = ( ('Grunddaten', { @@ -114,11 +114,11 @@ class VorgabeInline(SortableInlineAdminMixin, NestedStackedInline): # Changed t }), ('Gültigkeit', { 'fields': (('gueltigkeit_von', 'gueltigkeit_bis'),), - 'classes': ('wide', 'collapse'), + 'classes': ('wide',), }), ('Verknüpfungen', { 'fields': (('referenzen', 'stichworte', 'relevanz'),), - 'classes': ('wide', 'collapse'), + 'classes': ('wide',), }), ) @@ -169,7 +169,7 @@ class DokumentAdmin(SortableAdminBase, NestedModelAdmin): ) class Media: - js = ('admin/js/vorgabe_toggle.js',) + js = ('admin/js/vorgabe_collapse.js',) css = { 'all': ('admin/css/vorgabe_border.css',) } diff --git a/static/admin/js/vorgabe_collapse.js b/static/admin/js/vorgabe_collapse.js index 1bd1341..68abffe 100644 --- a/static/admin/js/vorgabe_collapse.js +++ b/static/admin/js/vorgabe_collapse.js @@ -1,21 +1,58 @@ window.addEventListener('load', function () { setTimeout(() => { - const vorgabenBlocks = document.querySelectorAll('.djn-dynamic-form-Standards-vorgabe'); - console.log("Found", vorgabenBlocks.length, "Vorgaben blocks"); + // Try different selectors for nested admin vorgabe elements + const selectors = [ + '.djn-dynamic-form-dokumente-vorgabe', + '.djn-dynamic-form-Standards-vorgabe', + '.inline-related[data-inline-type="stacked"]', + '.nested-inline' + ]; + + let vorgabenBlocks = []; + for (const selector of selectors) { + vorgabenBlocks = document.querySelectorAll(selector); + if (vorgabenBlocks.length > 0) { + console.log("Found", vorgabenBlocks.length, "Vorgaben blocks with selector:", selector); + break; + } + } + + if (vorgabenBlocks.length === 0) { + console.log("No Vorgaben blocks found, trying fallback..."); + // Fallback: look for any inline with vorgabe in the class + vorgabenBlocks = document.querySelectorAll('[class*="vorgabe"]'); + } vorgabenBlocks.forEach((block, index) => { - const header = document.createElement('div'); - header.className = 'vorgabe-toggle-header'; - header.innerHTML = `▼ Vorgabe ${index + 1}`; - header.style.cursor = 'pointer'; - - block.parentNode.insertBefore(header, block); - - header.addEventListener('click', () => { - const isHidden = block.style.display === 'none'; - block.style.display = isHidden ? '' : 'none'; - header.innerHTML = `${isHidden ? '▼' : '▶'} Vorgabe ${index + 1}`; - }); + // Find the existing title/header within the vorgabe block + const existingHeader = block.querySelector('h3, .inline-label, .module h2, .djn-inline-header'); + + if (existingHeader) { + // Make the existing header clickable for collapse/expand + existingHeader.style.cursor = 'pointer'; + existingHeader.addEventListener('click', (e) => { + e.preventDefault(); + e.stopPropagation(); + + // Find all content to collapse - everything except the header itself + const allChildren = Array.from(block.children); + const contentElements = allChildren.filter(child => child !== existingHeader && !child.contains(existingHeader)); + + contentElements.forEach(element => { + const isHidden = element.style.display === 'none'; + element.style.display = isHidden ? '' : 'none'; + }); + + // Update the header text to show collapse state + const originalText = existingHeader.textContent.replace(/[▼▶]\s*/, ''); + const anyHidden = contentElements.some(el => el.style.display === 'none'); + existingHeader.innerHTML = `${anyHidden ? '▶' : '▼'} ${originalText}`; + }); + + // Add initial collapse indicator + const originalText = existingHeader.textContent; + existingHeader.innerHTML = `▼ ${originalText}`; + } }); - }, 500); // wait 500ms to allow nested inlines to render + }, 1000); // wait longer to allow nested inlines to render });