... | ... |
@@ -1,4 +1,4 @@ |
1 | 1 |
<h3><?= $this->generateLabel().$this->xlabel ?></h3> |
2 |
-<div class="grid-container" data-rows="<?= $this->intRows ?>" data-cols="<?= $this->intCols ?>" data-field-id="<?= $this->id ?>"> |
|
2 |
+<div class="vr--grid-pos-container" data-rows="<?= $this->intRows ?>" data-cols="<?= $this->intCols ?>" data-field-id="ctrl_<?= $this->id ?>"> |
|
3 | 3 |
</div> |
4 | 4 |
<input type="hidden" name="<?= $this->id ?>" id="ctrl_<?= $this->id ?>" value="<?= $this->value ?>"> |
5 | 5 |
\ No newline at end of file |
... | ... |
@@ -6,46 +6,46 @@ |
6 | 6 |
--header-bg: var(--gp-primary); |
7 | 7 |
} |
8 | 8 |
|
9 |
-.grid-container { |
|
9 |
+.vr--grid-pos-container { |
|
10 | 10 |
margin: 3px 0; |
11 | 11 |
display: grid; |
12 | 12 |
grid-template-columns: repeat(6, 1fr); |
13 | 13 |
grid-gap: 5px; |
14 | 14 |
} |
15 |
-.grid-container[data-cols="1"] { |
|
15 |
+.vr--grid-pos-container[data-cols="1"] { |
|
16 | 16 |
grid-template-columns: repeat(1, 1fr); |
17 | 17 |
} |
18 |
-.grid-container[data-cols="2"] { |
|
18 |
+.vr--grid-pos-container[data-cols="2"] { |
|
19 | 19 |
grid-template-columns: repeat(2, 1fr); |
20 | 20 |
} |
21 |
-.grid-container[data-cols="3"] { |
|
21 |
+.vr--grid-pos-container[data-cols="3"] { |
|
22 | 22 |
grid-template-columns: repeat(3, 1fr); |
23 | 23 |
} |
24 |
-.grid-container[data-cols="4"] { |
|
24 |
+.vr--grid-pos-container[data-cols="4"] { |
|
25 | 25 |
grid-template-columns: repeat(4, 1fr); |
26 | 26 |
} |
27 |
-.grid-container[data-cols="5"] { |
|
27 |
+.vr--grid-pos-container[data-cols="5"] { |
|
28 | 28 |
grid-template-columns: repeat(5, 1fr); |
29 | 29 |
} |
30 |
-.grid-container[data-cols="6"] { |
|
30 |
+.vr--grid-pos-container[data-cols="6"] { |
|
31 | 31 |
grid-template-columns: repeat(6, 1fr); |
32 | 32 |
} |
33 |
-.grid-container[data-cols="7"] { |
|
33 |
+.vr--grid-pos-container[data-cols="7"] { |
|
34 | 34 |
grid-template-columns: repeat(7, 1fr); |
35 | 35 |
} |
36 |
-.grid-container[data-cols="8"] { |
|
36 |
+.vr--grid-pos-container[data-cols="8"] { |
|
37 | 37 |
grid-template-columns: repeat(8, 1fr); |
38 | 38 |
} |
39 |
-.grid-container[data-cols="9"] { |
|
39 |
+.vr--grid-pos-container[data-cols="9"] { |
|
40 | 40 |
grid-template-columns: repeat(9, 1fr); |
41 | 41 |
} |
42 |
-.grid-container[data-cols="10"] { |
|
42 |
+.vr--grid-pos-container[data-cols="10"] { |
|
43 | 43 |
grid-template-columns: repeat(10, 1fr); |
44 | 44 |
} |
45 |
-.grid-container[data-cols="11"] { |
|
45 |
+.vr--grid-pos-container[data-cols="11"] { |
|
46 | 46 |
grid-template-columns: repeat(11, 1fr); |
47 | 47 |
} |
48 |
-.grid-container[data-cols="12"] { |
|
48 |
+.vr--grid-pos-container[data-cols="12"] { |
|
49 | 49 |
grid-template-columns: repeat(12, 1fr); |
50 | 50 |
} |
51 | 51 |
|
... | ... |
@@ -1 +1 @@ |
1 |
-:root{--gp-primary:#a80556;--gp-primary-rgb:168, 5, 86;--contao:var(--gp-primary);--contao-rgb:var(--gp-primary-rgb);--header-bg:var(--gp-primary)}.grid-container{margin:3px 0;display:grid;grid-template-columns:repeat(6,1fr);grid-gap:5px}.grid-container[data-cols="1"]{grid-template-columns:repeat(1,1fr)}.grid-container[data-cols="2"]{grid-template-columns:repeat(2,1fr)}.grid-container[data-cols="3"]{grid-template-columns:repeat(3,1fr)}.grid-container[data-cols="4"]{grid-template-columns:repeat(4,1fr)}.grid-container[data-cols="5"]{grid-template-columns:repeat(5,1fr)}.grid-container[data-cols="6"]{grid-template-columns:repeat(6,1fr)}.grid-container[data-cols="7"]{grid-template-columns:repeat(7,1fr)}.grid-container[data-cols="8"]{grid-template-columns:repeat(8,1fr)}.grid-container[data-cols="9"]{grid-template-columns:repeat(9,1fr)}.grid-container[data-cols="10"]{grid-template-columns:repeat(10,1fr)}.grid-container[data-cols="11"]{grid-template-columns:repeat(11,1fr)}.grid-container[data-cols="12"]{grid-template-columns:repeat(12,1fr)}.grid-cell{height:30px;border:1px solid #ccc;cursor:pointer}.grid-cell:hover{background-color:rgba(var(--contao-rgb),.3)}.grid-cell.selected{background-color:var(--contao)} |
|
2 | 1 |
\ No newline at end of file |
2 |
+:root{--gp-primary:#a80556;--gp-primary-rgb:168, 5, 86;--contao:var(--gp-primary);--contao-rgb:var(--gp-primary-rgb);--header-bg:var(--gp-primary)}.vr--grid-pos-container{margin:3px 0;display:grid;grid-template-columns:repeat(6,1fr);grid-gap:5px}.vr--grid-pos-container[data-cols="1"]{grid-template-columns:repeat(1,1fr)}.vr--grid-pos-container[data-cols="2"]{grid-template-columns:repeat(2,1fr)}.vr--grid-pos-container[data-cols="3"]{grid-template-columns:repeat(3,1fr)}.vr--grid-pos-container[data-cols="4"]{grid-template-columns:repeat(4,1fr)}.vr--grid-pos-container[data-cols="5"]{grid-template-columns:repeat(5,1fr)}.vr--grid-pos-container[data-cols="6"]{grid-template-columns:repeat(6,1fr)}.vr--grid-pos-container[data-cols="7"]{grid-template-columns:repeat(7,1fr)}.vr--grid-pos-container[data-cols="8"]{grid-template-columns:repeat(8,1fr)}.vr--grid-pos-container[data-cols="9"]{grid-template-columns:repeat(9,1fr)}.vr--grid-pos-container[data-cols="10"]{grid-template-columns:repeat(10,1fr)}.vr--grid-pos-container[data-cols="11"]{grid-template-columns:repeat(11,1fr)}.vr--grid-pos-container[data-cols="12"]{grid-template-columns:repeat(12,1fr)}.grid-cell{height:30px;border:1px solid #ccc;cursor:pointer}.grid-cell:hover{background-color:rgba(var(--contao-rgb),.3)}.grid-cell.selected{background-color:var(--contao)} |
|
3 | 3 |
\ No newline at end of file |
... | ... |
@@ -1,95 +1,102 @@ |
1 | 1 |
function init() { |
2 |
- const gridContainer = document.querySelector('.grid-container'); |
|
2 |
+ const gridContainers = document.querySelectorAll('.vr--grid-pos-container'); |
|
3 | 3 |
|
4 |
- if (!gridContainer) return; |
|
4 |
+ if (!gridContainers.length) return; |
|
5 | 5 |
|
6 |
- // Werte aus den data-Attributen holen oder Standardwerte setzen |
|
7 |
- const gridRows = parseInt(gridContainer.dataset.rows) || 1; // Standardwert für Reihen: 5 |
|
8 |
- const gridCols = parseInt(gridContainer.dataset.cols) || 6; // Standardwert für Spalten: 5 |
|
9 |
- let selectedIndices = []; |
|
10 |
- |
|
11 |
- // Grid erstellen |
|
12 |
- const fragment = document.createDocumentFragment(); |
|
13 |
- // Erstelle die Zellen basierend auf Reihen und Spalten (gridRows * gridCols) |
|
14 |
- for (let i = 0; i < gridRows * gridCols; i++) |
|
6 |
+ for (const gridContainer of gridContainers) |
|
15 | 7 |
{ |
16 |
- const gridItem = document.createElement('div'); |
|
17 |
- gridItem.classList.add('grid-cell'); |
|
18 |
- gridItem.dataset.index = i; // Weise jeder Zelle ihren Index zu |
|
19 |
- gridItem.addEventListener('click', () => toggleCell(i)); // Event für Klick hinzufügen |
|
20 |
- fragment.appendChild(gridItem); |
|
8 |
+ |
|
9 |
+ // Werte aus den data-Attributen holen oder Standardwerte setzen |
|
10 |
+ gridContainer.gridRows = parseInt(gridContainer.dataset.rows) || 1; // Standardwert für Reihen: 5 |
|
11 |
+ gridContainer.gridCols = parseInt(gridContainer.dataset.cols) || 6; // Standardwert für Spalten: 5 |
|
12 |
+ gridContainer.dataField = document.getElementById(gridContainer.dataset.fieldId); |
|
13 |
+ |
|
14 |
+ gridContainer.selectedIndices = gridContainer.selectedIndices || []; |
|
15 |
+ |
|
16 |
+ // Grid erstellen |
|
17 |
+ const fragment = document.createDocumentFragment(); |
|
18 |
+ // Erstelle die Zellen basierend auf Reihen und Spalten (gridRows * gridCols) |
|
19 |
+ for (let i = 0; i < gridContainer.gridRows * gridContainer.gridCols; i++) |
|
20 |
+ { |
|
21 |
+ const gridItem = document.createElement('div'); |
|
22 |
+ gridItem.classList.add('grid-cell'); |
|
23 |
+ gridItem.dataset.index = i; // Weise jeder Zelle ihren Index zu |
|
24 |
+ gridItem.addEventListener('click', () => toggleCell(gridContainer,i)); // Event für Klick hinzufügen |
|
25 |
+ fragment.appendChild(gridItem); |
|
26 |
+ } |
|
27 |
+ gridContainer.appendChild(fragment); |
|
28 |
+ loadSelection(gridContainer); |
|
21 | 29 |
} |
22 |
- gridContainer.appendChild(fragment); |
|
23 | 30 |
|
24 | 31 |
/** |
25 | 32 |
* Zelle ein-/auswählen |
26 | 33 |
* @param {number} index - Der Index der Zelle |
27 | 34 |
*/ |
28 |
- function toggleCell(index) { |
|
29 |
- if (selectedIndices.includes(index)) |
|
35 |
+ function toggleCell(gridContainer,index) { |
|
36 |
+ if (gridContainer.selectedIndices.includes(index)) |
|
30 | 37 |
{ |
31 | 38 |
// Zelle abwählen |
32 |
- removeRowOrColumn(index); |
|
39 |
+ removeRowOrColumn(gridContainer,index); |
|
33 | 40 |
} else |
34 | 41 |
{ |
35 | 42 |
// Zelle hinzufügen |
36 |
- selectedIndices.push(index); |
|
37 |
- fillSelection(); // Rechteck auffüllen |
|
43 |
+ gridContainer.selectedIndices.push(index); |
|
44 |
+ fillSelection(gridContainer); // Rechteck auffüllen |
|
38 | 45 |
} |
39 | 46 |
|
40 |
- updateGrid(); // Visuelle Aktualisierung |
|
41 |
- saveSelection(); // Speicherung der Auswahl |
|
47 |
+ updateGrid(gridContainer); // Visuelle Aktualisierung |
|
48 |
+ saveSelection(gridContainer); // Speicherung der Auswahl |
|
42 | 49 |
} |
43 | 50 |
|
44 | 51 |
/** |
45 | 52 |
* Entfernt eine Zeile oder eine Spalte basierend auf dem Index |
46 | 53 |
* @param {number} index - Der Index der Zelle |
47 | 54 |
*/ |
48 |
- function removeRowOrColumn(index) { |
|
49 |
- const row = Math.floor(index / gridCols); // Berechnet die aktuelle Reihe |
|
50 |
- const col = index % gridCols; // Berechnet die aktuelle Spalte |
|
55 |
+ function removeRowOrColumn(gridContainer,index) { |
|
56 |
+ const row = Math.floor(index / gridContainer.gridCols); // Berechnet die aktuelle Reihe |
|
57 |
+ const col = index % gridContainer.gridCols; // Berechnet die aktuelle Spalte |
|
51 | 58 |
|
52 | 59 |
if (col === 0) |
53 | 60 |
{ |
54 | 61 |
// Entferne die gesamte Reihe, wenn das Feld in der ersten Spalte ist |
55 | 62 |
// UND entferne alle darunterliegenden Reihen |
56 |
- selectedIndices = selectedIndices.filter(cell => { |
|
57 |
- const cellRow = Math.floor(cell / gridCols); |
|
63 |
+ gridContainer.selectedIndices = gridContainer.selectedIndices.filter(cell => { |
|
64 |
+ const cellRow = Math.floor(cell / gridContainer.gridCols); |
|
58 | 65 |
return cellRow < row; // Entferne alle Reihen >= der aktuellen |
59 | 66 |
}); |
60 | 67 |
} else |
61 | 68 |
{ |
62 | 69 |
// Entferne die gesamte Spalte, wenn das Feld NICHT in der ersten Spalte ist |
63 |
- selectedIndices = selectedIndices.filter(cell => { |
|
64 |
- const cellCol = cell % gridCols; |
|
70 |
+ gridContainer.selectedIndices = gridContainer.selectedIndices.filter(cell => { |
|
71 |
+ const cellCol = cell % gridContainer.gridCols; |
|
65 | 72 |
return cellCol !== col; |
66 | 73 |
}); |
67 | 74 |
|
68 | 75 |
// Prüfe, ob Spalten rechts entfernt werden müssen, um Lücken zu vermeiden |
69 |
- adjustRectangleAfterColumnRemoval(); |
|
76 |
+ adjustRectangleAfterColumnRemoval(gridContainer); |
|
70 | 77 |
} |
71 | 78 |
} |
72 | 79 |
|
73 | 80 |
/** |
74 | 81 |
* Passt das Rechteck an, indem leere Spalten rechts entfernt werden |
75 | 82 |
*/ |
76 |
- function adjustRectangleAfterColumnRemoval() { |
|
77 |
- if (selectedIndices.length === 0) return; |
|
83 |
+ function adjustRectangleAfterColumnRemoval(gridContainer) { |
|
84 |
+ if (gridContainer.selectedIndices.length === 0) return; |
|
78 | 85 |
|
79 | 86 |
// Ermittle die minimalen und maximalen Spalten des bestehenden Rechtecks |
80 |
- const firstCol = Math.min(...selectedIndices.map(cell => cell % gridCols)); |
|
81 |
- const lastCol = Math.max(...selectedIndices.map(cell => cell % gridCols)); |
|
87 |
+ const firstCol = Math.min(...gridContainer.selectedIndices.map(cell => cell % gridContainer.gridCols)); |
|
88 |
+ const lastCol = Math.max(...gridContainer.selectedIndices.map(cell => cell % gridContainer.gridCols)); |
|
82 | 89 |
|
83 | 90 |
// Prüfe jede Spalte von links nach rechts |
84 | 91 |
for (let col = firstCol; col <= lastCol; col++) |
85 | 92 |
{ |
86 | 93 |
// Überprüfen, ob diese Spalte komplett leer ist |
87 |
- const isColumnEmpty = !selectedIndices.some(cell => cell % gridCols === col); |
|
94 |
+ const isColumnEmpty = !gridContainer.selectedIndices.some(cell => cell % gridContainer.gridCols === col); |
|
88 | 95 |
|
89 | 96 |
if (isColumnEmpty) |
90 | 97 |
{ |
91 | 98 |
// Entferne alle Zellen in Spalten rechts von der leeren Spalte |
92 |
- selectedIndices = selectedIndices.filter(cell => cell % gridCols < col); |
|
99 |
+ gridContainer.selectedIndices = gridContainer.selectedIndices.filter(cell => cell % gridContainer.gridCols < col); |
|
93 | 100 |
break; // Stoppe, wenn wir eine leere Spalte finden |
94 | 101 |
} |
95 | 102 |
} |
... | ... |
@@ -98,14 +105,14 @@ function init() { |
98 | 105 |
/** |
99 | 106 |
* Füllt die Auswahl als Rechteck aus |
100 | 107 |
*/ |
101 |
- function fillSelection() { |
|
102 |
- if (selectedIndices.length === 0) return; |
|
108 |
+ function fillSelection(gridContainer) { |
|
109 |
+ if (gridContainer.selectedIndices.length === 0) return; |
|
103 | 110 |
|
104 | 111 |
// Ermittle die minimalen und maximalen Indizes |
105 |
- const firstRow = Math.min(...selectedIndices.map(cell => Math.floor(cell / gridCols))); |
|
106 |
- const lastRow = Math.max(...selectedIndices.map(cell => Math.floor(cell / gridCols))); |
|
107 |
- const firstCol = Math.min(...selectedIndices.map(cell => cell % gridCols)); |
|
108 |
- const lastCol = Math.max(...selectedIndices.map(cell => cell % gridCols)); |
|
112 |
+ const firstRow = Math.min(...gridContainer.selectedIndices.map(cell => Math.floor(cell / gridContainer.gridCols))); |
|
113 |
+ const lastRow = Math.max(...gridContainer.selectedIndices.map(cell => Math.floor(cell / gridContainer.gridCols))); |
|
114 |
+ const firstCol = Math.min(...gridContainer.selectedIndices.map(cell => cell % gridContainer.gridCols)); |
|
115 |
+ const lastCol = Math.max(...gridContainer.selectedIndices.map(cell => cell % gridContainer.gridCols)); |
|
109 | 116 |
|
110 | 117 |
// Rechteck auffüllen: Alle Zellen zwischen den Ecken hinzufügen |
111 | 118 |
const newSelection = []; |
... | ... |
@@ -113,25 +120,25 @@ function init() { |
113 | 120 |
{ |
114 | 121 |
for (let col = firstCol; col <= lastCol; col++) |
115 | 122 |
{ |
116 |
- const cellIndex = row * gridCols + col; |
|
123 |
+ const cellIndex = row * gridContainer.gridCols + col; |
|
117 | 124 |
newSelection.push(cellIndex); |
118 | 125 |
} |
119 | 126 |
} |
120 | 127 |
|
121 |
- selectedIndices = newSelection; // Aktualisiere die Auswahl |
|
128 |
+ gridContainer.selectedIndices = newSelection; // Aktualisiere die Auswahl |
|
122 | 129 |
} |
123 | 130 |
|
124 | 131 |
/** |
125 | 132 |
* Aktualisiert die visuelle Darstellung des Grids |
126 | 133 |
*/ |
127 |
- function updateGrid() { |
|
134 |
+ function updateGrid(gridContainer) { |
|
128 | 135 |
// Entferne die "selected"-Klasse von allen Zellen |
129 | 136 |
gridContainer.querySelectorAll('.grid-cell').forEach(cell => { |
130 | 137 |
cell.classList.remove('selected'); |
131 | 138 |
}); |
132 | 139 |
|
133 | 140 |
// Füge die "selected"-Klasse zu den ausgewählten Zellen hinzu |
134 |
- selectedIndices.forEach(index => { |
|
141 |
+ gridContainer.selectedIndices.forEach(index => { |
|
135 | 142 |
gridContainer |
136 | 143 |
.querySelector(`.grid-cell[data-index="${index}"]`) |
137 | 144 |
?.classList.add('selected'); |
... | ... |
@@ -141,11 +148,23 @@ function init() { |
141 | 148 |
/** |
142 | 149 |
* Speichert die Auswahl in einem versteckten Eingabeelement |
143 | 150 |
*/ |
144 |
- function saveSelection() { |
|
145 |
- const gridDataInput = document.getElementById('ctrl_vr_gpw_grid'); |
|
151 |
+ function saveSelection(gridContainer) { |
|
152 |
+ const gridDataInput = gridContainer.dataField; |
|
153 |
+ if (gridDataInput) |
|
154 |
+ { |
|
155 |
+ gridDataInput.value = JSON.stringify(gridContainer.selectedIndices); |
|
156 |
+ } |
|
157 |
+ } |
|
158 |
+ |
|
159 |
+ /** |
|
160 |
+ * Lädt die Auswahl aus einem versteckten Eingabeelement |
|
161 |
+ */ |
|
162 |
+ function loadSelection(gridContainer) { |
|
163 |
+ const gridDataInput = gridContainer.dataField; |
|
146 | 164 |
if (gridDataInput) |
147 | 165 |
{ |
148 |
- gridDataInput.value = JSON.stringify(selectedIndices); |
|
166 |
+ gridContainer.selectedIndices = JSON.parse(gridDataInput.value); |
|
167 |
+ updateGrid(gridContainer); |
|
149 | 168 |
} |
150 | 169 |
} |
151 | 170 |
} |
... | ... |
@@ -1 +1 @@ |
1 |
-document.addEventListener("DOMContentLoaded",()=>{const gridContainer=document.querySelector(".grid-container");if(!gridContainer)return;const gridRows=parseInt(gridContainer.dataset.rows)||1;const gridCols=parseInt(gridContainer.dataset.cols)||6;let selectedIndices=[];const fragment=document.createDocumentFragment();for(let i=0;i<gridRows*gridCols;i++){const gridItem=document.createElement("div");gridItem.classList.add("grid-cell");gridItem.dataset.index=i;gridItem.addEventListener("click",()=>toggleCell(i));fragment.appendChild(gridItem)}gridContainer.appendChild(fragment);function toggleCell(index){if(selectedIndices.includes(index)){removeRowOrColumn(index)}else{selectedIndices.push(index);fillSelection()}updateGrid();saveSelection()}function removeRowOrColumn(index){const row=Math.floor(index/gridCols);const col=index%gridCols;if(col===0){selectedIndices=selectedIndices.filter(cell=>{const cellRow=Math.floor(cell/gridCols);return cellRow<row})}else{selectedIndices=selectedIndices.filter(cell=>{const cellCol=cell%gridCols;return cellCol!==col});adjustRectangleAfterColumnRemoval()}}function adjustRectangleAfterColumnRemoval(){if(selectedIndices.length===0)return;const firstCol=Math.min(...selectedIndices.map(cell=>cell%gridCols));const lastCol=Math.max(...selectedIndices.map(cell=>cell%gridCols));for(let col=firstCol;col<=lastCol;col++){const isColumnEmpty=!selectedIndices.some(cell=>cell%gridCols===col);if(isColumnEmpty){selectedIndices=selectedIndices.filter(cell=>cell%gridCols<col);break}}}function fillSelection(){if(selectedIndices.length===0)return;const firstRow=Math.min(...selectedIndices.map(cell=>Math.floor(cell/gridCols)));const lastRow=Math.max(...selectedIndices.map(cell=>Math.floor(cell/gridCols)));const firstCol=Math.min(...selectedIndices.map(cell=>cell%gridCols));const lastCol=Math.max(...selectedIndices.map(cell=>cell%gridCols));const newSelection=[];for(let row=firstRow;row<=lastRow;row++){for(let col=firstCol;col<=lastCol;col++){const cellIndex=row*gridCols+col;newSelection.push(cellIndex)}}selectedIndices=newSelection}function updateGrid(){gridContainer.querySelectorAll(".grid-cell").forEach(cell=>{cell.classList.remove("selected")});selectedIndices.forEach(index=>{gridContainer.querySelector(`.grid-cell[data-index="${index}"]`)?.classList.add("selected")})}function saveSelection(){const gridDataInput=document.getElementById("grid-data");if(gridDataInput){gridDataInput.value=JSON.stringify(selectedIndices)}}}); |
|
2 | 1 |
\ No newline at end of file |
2 |
+function init(){const gridContainers=document.querySelectorAll(".vr--grid-pos-container");if(!gridContainers.length)return;for(const gridContainer of gridContainers){gridContainer.gridRows=parseInt(gridContainer.dataset.rows)||1;gridContainer.gridCols=parseInt(gridContainer.dataset.cols)||6;gridContainer.dataField=document.getElementById(gridContainer.dataset.fieldId);gridContainer.selectedIndices=gridContainer.selectedIndices||[];const fragment=document.createDocumentFragment();for(let i=0;i<gridContainer.gridRows*gridContainer.gridCols;i++){const gridItem=document.createElement("div");gridItem.classList.add("grid-cell");gridItem.dataset.index=i;gridItem.addEventListener("click",()=>toggleCell(gridContainer,i));fragment.appendChild(gridItem)}gridContainer.appendChild(fragment);loadSelection(gridContainer)}function toggleCell(gridContainer,index){if(gridContainer.selectedIndices.includes(index)){removeRowOrColumn(gridContainer,index)}else{gridContainer.selectedIndices.push(index);fillSelection(gridContainer)}updateGrid(gridContainer);saveSelection(gridContainer)}function removeRowOrColumn(gridContainer,index){const row=Math.floor(index/gridContainer.gridCols);const col=index%gridContainer.gridCols;if(col===0){gridContainer.selectedIndices=gridContainer.selectedIndices.filter(cell=>{const cellRow=Math.floor(cell/gridContainer.gridCols);return cellRow<row})}else{gridContainer.selectedIndices=gridContainer.selectedIndices.filter(cell=>{const cellCol=cell%gridContainer.gridCols;return cellCol!==col});adjustRectangleAfterColumnRemoval(gridContainer)}}function adjustRectangleAfterColumnRemoval(gridContainer){if(gridContainer.selectedIndices.length===0)return;const firstCol=Math.min(...gridContainer.selectedIndices.map(cell=>cell%gridContainer.gridCols));const lastCol=Math.max(...gridContainer.selectedIndices.map(cell=>cell%gridContainer.gridCols));for(let col=firstCol;col<=lastCol;col++){const isColumnEmpty=!gridContainer.selectedIndices.some(cell=>cell%gridContainer.gridCols===col);if(isColumnEmpty){gridContainer.selectedIndices=gridContainer.selectedIndices.filter(cell=>cell%gridContainer.gridCols<col);break}}}function fillSelection(gridContainer){if(gridContainer.selectedIndices.length===0)return;const firstRow=Math.min(...gridContainer.selectedIndices.map(cell=>Math.floor(cell/gridContainer.gridCols)));const lastRow=Math.max(...gridContainer.selectedIndices.map(cell=>Math.floor(cell/gridContainer.gridCols)));const firstCol=Math.min(...gridContainer.selectedIndices.map(cell=>cell%gridContainer.gridCols));const lastCol=Math.max(...gridContainer.selectedIndices.map(cell=>cell%gridContainer.gridCols));const newSelection=[];for(let row=firstRow;row<=lastRow;row++){for(let col=firstCol;col<=lastCol;col++){const cellIndex=row*gridContainer.gridCols+col;newSelection.push(cellIndex)}}gridContainer.selectedIndices=newSelection}function updateGrid(gridContainer){gridContainer.querySelectorAll(".grid-cell").forEach(cell=>{cell.classList.remove("selected")});gridContainer.selectedIndices.forEach(index=>{gridContainer.querySelector(`.grid-cell[data-index="${index}"]`)?.classList.add("selected")})}function saveSelection(gridContainer){const gridDataInput=gridContainer.dataField;if(gridDataInput){gridDataInput.value=JSON.stringify(selectedIndices)}}function loadSelection(gridContainer){const gridDataInput=gridContainer.dataField;if(gridDataInput){selectedIndices=JSON.parse(gridDataInput.value);updateGrid(gridContainer)}}}document.addEventListener("DOMContentLoaded",()=>{init()});document.addEventListener("turbo:render",()=>{init()}); |
|
3 | 3 |
\ No newline at end of file |
4 | 4 |
deleted file mode 100644 |
... | ... |
@@ -1,101 +0,0 @@ |
1 |
-document.addEventListener('DOMContentLoaded', () => { |
|
2 |
- const gridContainer = document.querySelector('.grid-container'); |
|
3 |
- const gridSize = 5; |
|
4 |
- let selectedIndices = []; |
|
5 |
- |
|
6 |
- if (!gridContainer) return; |
|
7 |
- |
|
8 |
- // Grid dynamisch erstellen |
|
9 |
- const fragment = document.createDocumentFragment(); |
|
10 |
- for (let i = 0; i < gridSize * gridSize; i++) { |
|
11 |
- const gridItem = document.createElement('div'); |
|
12 |
- gridItem.classList.add('grid-cell'); |
|
13 |
- gridItem.dataset.index = i; |
|
14 |
- gridItem.addEventListener('click', () => toggleCell(i)); |
|
15 |
- fragment.appendChild(gridItem); |
|
16 |
- } |
|
17 |
- gridContainer.appendChild(fragment); |
|
18 |
- |
|
19 |
- function toggleCell(index) { |
|
20 |
- const gridItem = gridContainer.querySelector(`.grid-cell[data-index="${index}"]`); |
|
21 |
- if (!gridItem) return; |
|
22 |
- |
|
23 |
- if (selectedIndices.includes(index)) { |
|
24 |
- // Entfernen, falls bereits ausgewählt |
|
25 |
- selectedIndices = selectedIndices.filter(cell => cell !== index); |
|
26 |
- gridItem.classList.remove('selected'); |
|
27 |
- } else if (isSelectable(index)) { |
|
28 |
- // Wählen, wenn erste oder angrenzende Zelle |
|
29 |
- selectedIndices.push(index); |
|
30 |
- gridItem.classList.add('selected'); |
|
31 |
- } else { |
|
32 |
- // Invalid, Auswahl zurücksetzen |
|
33 |
- resetSelection(index); |
|
34 |
- } |
|
35 |
- validateSelection(); |
|
36 |
- saveSelection(); |
|
37 |
- } |
|
38 |
- |
|
39 |
- function isSelectable(index) { |
|
40 |
- return selectedIndices.length === 0 || selectedIndices.some(selected => isAdjacent(index, selected)); |
|
41 |
- } |
|
42 |
- |
|
43 |
- function resetSelection(index) { |
|
44 |
- selectedIndices = [index]; |
|
45 |
- resetGrid(); |
|
46 |
- gridContainer.querySelector(`.grid-cell[data-index="${index}"]`)?.classList.add('selected'); |
|
47 |
- } |
|
48 |
- |
|
49 |
- function isAdjacent(index1, index2) { |
|
50 |
- const rowDiff = Math.abs(Math.floor(index1 / gridSize) - Math.floor(index2 / gridSize)); |
|
51 |
- const colDiff = Math.abs(index1 % gridSize - index2 % gridSize); |
|
52 |
- return (rowDiff === 1 && colDiff === 0) || (rowDiff === 0 && colDiff === 1); |
|
53 |
- } |
|
54 |
- |
|
55 |
- function validateSelection() { |
|
56 |
- if (selectedIndices.length <= 1) return; |
|
57 |
- |
|
58 |
- const validSelection = [selectedIndices[0]]; |
|
59 |
- const remainingCells = selectedIndices.slice(1); |
|
60 |
- |
|
61 |
- while (remainingCells.length > 0) { |
|
62 |
- let foundAdjacent = false; |
|
63 |
- |
|
64 |
- for (let i = 0; i < remainingCells.length; i++) { |
|
65 |
- if (validSelection.some(selected => isAdjacent(remainingCells[i], selected))) { |
|
66 |
- validSelection.push(remainingCells[i]); |
|
67 |
- remainingCells.splice(i, 1); |
|
68 |
- foundAdjacent = true; |
|
69 |
- break; |
|
70 |
- } |
|
71 |
- } |
|
72 |
- |
|
73 |
- if (!foundAdjacent) { |
|
74 |
- selectedIndices = validSelection; |
|
75 |
- resetGrid(); |
|
76 |
- highlightSelection(); |
|
77 |
- return; |
|
78 |
- } |
|
79 |
- } |
|
80 |
- |
|
81 |
- selectedIndices = validSelection; |
|
82 |
- highlightSelection(); |
|
83 |
- } |
|
84 |
- |
|
85 |
- function resetGrid() { |
|
86 |
- gridContainer.querySelectorAll('.grid-cell').forEach(cell => cell.classList.remove('selected')); |
|
87 |
- } |
|
88 |
- |
|
89 |
- function highlightSelection() { |
|
90 |
- selectedIndices.forEach(index => { |
|
91 |
- gridContainer.querySelector(`.grid-cell[data-index="${index}"]`)?.classList.add('selected'); |
|
92 |
- }); |
|
93 |
- } |
|
94 |
- |
|
95 |
- function saveSelection() { |
|
96 |
- const gridDataInput = document.getElementById(gridContainer.dataset.fieldId); |
|
97 |
- if (gridDataInput) { |
|
98 |
- gridDataInput.value = JSON.stringify(selectedIndices); |
|
99 |
- } |
|
100 |
- } |
|
101 |
-}); |