1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,15 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+declare(strict_types=1); |
|
4 |
+ |
|
5 |
+/* |
|
6 |
+ * This file is part of vonRotenberg Coretools Bundle. |
|
7 |
+ * |
|
8 |
+ * (c) vonRotenberg |
|
9 |
+ * |
|
10 |
+ * @license proprietary |
|
11 |
+ */ |
|
12 |
+ |
|
13 |
+use vonRotenberg\CoretoolsBundle\Widget\GridPosition; |
|
14 |
+ |
|
15 |
+$GLOBALS['BE_FFL']['gridPosition'] = GridPosition::class; |
0 | 16 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,3 @@ |
1 |
+<div class="grid-container" data-rows="<?= $this->intRows ?>" data-cols="<?= $this->intCols ?>" data-field-id="<?= $this->id ?>"> |
|
2 |
+</div> |
|
3 |
+<input type="hidden" name="<?= $this->id ?>" id="<?= $this->id ?>" value="<?= $this->value ?>"> |
|
0 | 4 |
\ No newline at end of file |
1 | 5 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,61 @@ |
1 |
+:root { |
|
2 |
+ --gp-primary: #a80556; |
|
3 |
+ --gp-primary-rgb: 168, 5, 86; |
|
4 |
+ --contao: var(--gp-primary); |
|
5 |
+ --contao-rgb: var(--gp-primary-rgb); |
|
6 |
+ --header-bg: var(--gp-primary); |
|
7 |
+} |
|
8 |
+ |
|
9 |
+.grid-container { |
|
10 |
+ display: grid; |
|
11 |
+ grid-template-columns: repeat(6, 1fr); |
|
12 |
+ grid-gap: 5px; |
|
13 |
+} |
|
14 |
+.grid-container[data-cols="1"] { |
|
15 |
+ grid-template-columns: repeat(1, 1fr); |
|
16 |
+} |
|
17 |
+.grid-container[data-cols="2"] { |
|
18 |
+ grid-template-columns: repeat(2, 1fr); |
|
19 |
+} |
|
20 |
+.grid-container[data-cols="3"] { |
|
21 |
+ grid-template-columns: repeat(3, 1fr); |
|
22 |
+} |
|
23 |
+.grid-container[data-cols="4"] { |
|
24 |
+ grid-template-columns: repeat(4, 1fr); |
|
25 |
+} |
|
26 |
+.grid-container[data-cols="5"] { |
|
27 |
+ grid-template-columns: repeat(5, 1fr); |
|
28 |
+} |
|
29 |
+.grid-container[data-cols="6"] { |
|
30 |
+ grid-template-columns: repeat(6, 1fr); |
|
31 |
+} |
|
32 |
+.grid-container[data-cols="7"] { |
|
33 |
+ grid-template-columns: repeat(7, 1fr); |
|
34 |
+} |
|
35 |
+.grid-container[data-cols="8"] { |
|
36 |
+ grid-template-columns: repeat(8, 1fr); |
|
37 |
+} |
|
38 |
+.grid-container[data-cols="9"] { |
|
39 |
+ grid-template-columns: repeat(9, 1fr); |
|
40 |
+} |
|
41 |
+.grid-container[data-cols="10"] { |
|
42 |
+ grid-template-columns: repeat(10, 1fr); |
|
43 |
+} |
|
44 |
+.grid-container[data-cols="11"] { |
|
45 |
+ grid-template-columns: repeat(11, 1fr); |
|
46 |
+} |
|
47 |
+.grid-container[data-cols="12"] { |
|
48 |
+ grid-template-columns: repeat(12, 1fr); |
|
49 |
+} |
|
50 |
+ |
|
51 |
+.grid-cell { |
|
52 |
+ height: 30px; |
|
53 |
+ border: 1px solid #ccc; |
|
54 |
+ cursor: pointer; |
|
55 |
+} |
|
56 |
+.grid-cell:hover { |
|
57 |
+ background-color: rgba(var(--contao-rgb), 0.3); |
|
58 |
+} |
|
59 |
+.grid-cell.selected { |
|
60 |
+ background-color: var(--contao); |
|
61 |
+} |
0 | 62 |
new file mode 100644 |
... | ... |
@@ -0,0 +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{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)} |
|
0 | 2 |
\ No newline at end of file |
1 | 3 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,33 @@ |
1 |
+:root { |
|
2 |
+ --gp-primary: #a80556; |
|
3 |
+ --gp-primary-rgb: 168, 5, 86; |
|
4 |
+ --contao: var(--gp-primary); |
|
5 |
+ --contao-rgb: var(--gp-primary-rgb); |
|
6 |
+ --header-bg: var(--gp-primary); |
|
7 |
+} |
|
8 |
+ |
|
9 |
+.grid-container { |
|
10 |
+ display: grid; |
|
11 |
+ grid-template-columns: repeat(6, 1fr); |
|
12 |
+ grid-gap: 5px; |
|
13 |
+ |
|
14 |
+ @for $i from 1 through 12 { |
|
15 |
+ &[data-cols="#{$i}"] { |
|
16 |
+ grid-template-columns: repeat($i, 1fr); |
|
17 |
+ } |
|
18 |
+ } |
|
19 |
+} |
|
20 |
+ |
|
21 |
+.grid-cell { |
|
22 |
+ height: 30px; |
|
23 |
+ border: 1px solid #ccc; |
|
24 |
+ cursor: pointer; |
|
25 |
+ |
|
26 |
+ &:hover { |
|
27 |
+ background-color: rgba(var(--contao-rgb),.3); |
|
28 |
+ } |
|
29 |
+ |
|
30 |
+ &.selected { |
|
31 |
+ background-color: var(--contao); |
|
32 |
+ } |
|
33 |
+} |
0 | 34 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,141 @@ |
1 |
+document.addEventListener('DOMContentLoaded', () => { |
|
2 |
+ const gridContainer = document.querySelector('.grid-container'); |
|
3 |
+ |
|
4 |
+ if (!gridContainer) return; |
|
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++) { |
|
15 |
+ const gridItem = document.createElement('div'); |
|
16 |
+ gridItem.classList.add('grid-cell'); |
|
17 |
+ gridItem.dataset.index = i; // Weise jeder Zelle ihren Index zu |
|
18 |
+ gridItem.addEventListener('click', () => toggleCell(i)); // Event für Klick hinzufügen |
|
19 |
+ fragment.appendChild(gridItem); |
|
20 |
+ } |
|
21 |
+ gridContainer.appendChild(fragment); |
|
22 |
+ |
|
23 |
+ /** |
|
24 |
+ * Zelle ein-/auswählen |
|
25 |
+ * @param {number} index - Der Index der Zelle |
|
26 |
+ */ |
|
27 |
+ function toggleCell(index) { |
|
28 |
+ if (selectedIndices.includes(index)) { |
|
29 |
+ // Zelle abwählen |
|
30 |
+ removeRowOrColumn(index); |
|
31 |
+ } else { |
|
32 |
+ // Zelle hinzufügen |
|
33 |
+ selectedIndices.push(index); |
|
34 |
+ fillSelection(); // Rechteck auffüllen |
|
35 |
+ } |
|
36 |
+ |
|
37 |
+ updateGrid(); // Visuelle Aktualisierung |
|
38 |
+ saveSelection(); // Speicherung der Auswahl |
|
39 |
+ } |
|
40 |
+ |
|
41 |
+ /** |
|
42 |
+ * Entfernt eine Zeile oder eine Spalte basierend auf dem Index |
|
43 |
+ * @param {number} index - Der Index der Zelle |
|
44 |
+ */ |
|
45 |
+ function removeRowOrColumn(index) { |
|
46 |
+ const row = Math.floor(index / gridCols); // Berechnet die aktuelle Reihe |
|
47 |
+ const col = index % gridCols; // Berechnet die aktuelle Spalte |
|
48 |
+ |
|
49 |
+ if (col === 0) { |
|
50 |
+ // Entferne die gesamte Reihe, wenn das Feld in der ersten Spalte ist |
|
51 |
+ // UND entferne alle darunterliegenden Reihen |
|
52 |
+ selectedIndices = selectedIndices.filter(cell => { |
|
53 |
+ const cellRow = Math.floor(cell / gridCols); |
|
54 |
+ return cellRow < row; // Entferne alle Reihen >= der aktuellen |
|
55 |
+ }); |
|
56 |
+ } else { |
|
57 |
+ // Entferne die gesamte Spalte, wenn das Feld NICHT in der ersten Spalte ist |
|
58 |
+ selectedIndices = selectedIndices.filter(cell => { |
|
59 |
+ const cellCol = cell % gridCols; |
|
60 |
+ return cellCol !== col; |
|
61 |
+ }); |
|
62 |
+ |
|
63 |
+ // Prüfe, ob Spalten rechts entfernt werden müssen, um Lücken zu vermeiden |
|
64 |
+ adjustRectangleAfterColumnRemoval(); |
|
65 |
+ } |
|
66 |
+ } |
|
67 |
+ |
|
68 |
+ /** |
|
69 |
+ * Passt das Rechteck an, indem leere Spalten rechts entfernt werden |
|
70 |
+ */ |
|
71 |
+ function adjustRectangleAfterColumnRemoval() { |
|
72 |
+ if (selectedIndices.length === 0) return; |
|
73 |
+ |
|
74 |
+ // Ermittle die minimalen und maximalen Spalten des bestehenden Rechtecks |
|
75 |
+ const firstCol = Math.min(...selectedIndices.map(cell => cell % gridCols)); |
|
76 |
+ const lastCol = Math.max(...selectedIndices.map(cell => cell % gridCols)); |
|
77 |
+ |
|
78 |
+ // Prüfe jede Spalte von links nach rechts |
|
79 |
+ for (let col = firstCol; col <= lastCol; col++) { |
|
80 |
+ // Überprüfen, ob diese Spalte komplett leer ist |
|
81 |
+ const isColumnEmpty = !selectedIndices.some(cell => cell % gridCols === col); |
|
82 |
+ |
|
83 |
+ if (isColumnEmpty) { |
|
84 |
+ // Entferne alle Zellen in Spalten rechts von der leeren Spalte |
|
85 |
+ selectedIndices = selectedIndices.filter(cell => cell % gridCols < col); |
|
86 |
+ break; // Stoppe, wenn wir eine leere Spalte finden |
|
87 |
+ } |
|
88 |
+ } |
|
89 |
+ } |
|
90 |
+ |
|
91 |
+ /** |
|
92 |
+ * Füllt die Auswahl als Rechteck aus |
|
93 |
+ */ |
|
94 |
+ function fillSelection() { |
|
95 |
+ if (selectedIndices.length === 0) return; |
|
96 |
+ |
|
97 |
+ // Ermittle die minimalen und maximalen Indizes |
|
98 |
+ const firstRow = Math.min(...selectedIndices.map(cell => Math.floor(cell / gridCols))); |
|
99 |
+ const lastRow = Math.max(...selectedIndices.map(cell => Math.floor(cell / gridCols))); |
|
100 |
+ const firstCol = Math.min(...selectedIndices.map(cell => cell % gridCols)); |
|
101 |
+ const lastCol = Math.max(...selectedIndices.map(cell => cell % gridCols)); |
|
102 |
+ |
|
103 |
+ // Rechteck auffüllen: Alle Zellen zwischen den Ecken hinzufügen |
|
104 |
+ const newSelection = []; |
|
105 |
+ for (let row = firstRow; row <= lastRow; row++) { |
|
106 |
+ for (let col = firstCol; col <= lastCol; col++) { |
|
107 |
+ const cellIndex = row * gridCols + col; |
|
108 |
+ newSelection.push(cellIndex); |
|
109 |
+ } |
|
110 |
+ } |
|
111 |
+ |
|
112 |
+ selectedIndices = newSelection; // Aktualisiere die Auswahl |
|
113 |
+ } |
|
114 |
+ |
|
115 |
+ /** |
|
116 |
+ * Aktualisiert die visuelle Darstellung des Grids |
|
117 |
+ */ |
|
118 |
+ function updateGrid() { |
|
119 |
+ // Entferne die "selected"-Klasse von allen Zellen |
|
120 |
+ gridContainer.querySelectorAll('.grid-cell').forEach(cell => { |
|
121 |
+ cell.classList.remove('selected'); |
|
122 |
+ }); |
|
123 |
+ |
|
124 |
+ // Füge die "selected"-Klasse zu den ausgewählten Zellen hinzu |
|
125 |
+ selectedIndices.forEach(index => { |
|
126 |
+ gridContainer |
|
127 |
+ .querySelector(`.grid-cell[data-index="${index}"]`) |
|
128 |
+ ?.classList.add('selected'); |
|
129 |
+ }); |
|
130 |
+ } |
|
131 |
+ |
|
132 |
+ /** |
|
133 |
+ * Speichert die Auswahl in einem versteckten Eingabeelement |
|
134 |
+ */ |
|
135 |
+ function saveSelection() { |
|
136 |
+ const gridDataInput = document.getElementById('grid-data'); |
|
137 |
+ if (gridDataInput) { |
|
138 |
+ gridDataInput.value = JSON.stringify(selectedIndices); |
|
139 |
+ } |
|
140 |
+ } |
|
141 |
+}); |
0 | 142 |
new file mode 100644 |
... | ... |
@@ -0,0 +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)}}}); |
|
0 | 2 |
\ No newline at end of file |
1 | 3 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,101 @@ |
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 |
+}); |
0 | 102 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,35 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+declare(strict_types=1); |
|
4 |
+ |
|
5 |
+namespace vonRotenberg\CoretoolsBundle\EventListener; |
|
6 |
+ |
|
7 |
+use Contao\CoreBundle\Routing\ScopeMatcher; |
|
8 |
+use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
|
9 |
+use Symfony\Component\HttpKernel\Event\RequestEvent; |
|
10 |
+use Symfony\Component\HttpKernel\KernelEvents; |
|
11 |
+ |
|
12 |
+class KernelRequestSubscriber implements EventSubscriberInterface |
|
13 |
+{ |
|
14 |
+ protected $scopeMatcher; |
|
15 |
+ |
|
16 |
+ public function __construct(ScopeMatcher $scopeMatcher) |
|
17 |
+ { |
|
18 |
+ $this->scopeMatcher = $scopeMatcher; |
|
19 |
+ } |
|
20 |
+ |
|
21 |
+ public static function getSubscribedEvents() |
|
22 |
+ { |
|
23 |
+ return [KernelEvents::REQUEST => 'onKernelRequest']; |
|
24 |
+ } |
|
25 |
+ |
|
26 |
+ public function onKernelRequest(RequestEvent $e): void |
|
27 |
+ { |
|
28 |
+ $request = $e->getRequest(); |
|
29 |
+ |
|
30 |
+ if ($this->scopeMatcher->isBackendRequest($request)) { |
|
31 |
+ $GLOBALS['TL_CSS'][] = 'bundles/vonrotenbergcoretools/css/grid_position_widget.min.css|static'; |
|
32 |
+ $GLOBALS['TL_JAVASCRIPT'][] = 'bundles/vonrotenbergcoretools/js/GridSelectionHandler.js|async'; |
|
33 |
+ } |
|
34 |
+ } |
|
35 |
+} |
0 | 36 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,51 @@ |
1 |
+<?php |
|
2 |
+ |
|
3 |
+declare(strict_types=1); |
|
4 |
+ |
|
5 |
+namespace vonRotenberg\CoretoolsBundle\Widget; |
|
6 |
+ |
|
7 |
+use Contao\Widget; |
|
8 |
+ |
|
9 |
+class GridPosition extends Widget |
|
10 |
+{ |
|
11 |
+ /** |
|
12 |
+ * @inheritdoc |
|
13 |
+ */ |
|
14 |
+ protected $strTemplate = 'be_grid_position'; |
|
15 |
+ |
|
16 |
+ protected $parent; |
|
17 |
+ |
|
18 |
+ protected $intCols = 6; |
|
19 |
+ |
|
20 |
+ protected $intRows = 1; |
|
21 |
+ |
|
22 |
+ public function __construct($arrAttributes = null) |
|
23 |
+ { |
|
24 |
+ parent::__construct($arrAttributes); |
|
25 |
+ |
|
26 |
+ $this->parent = $this->activeRecord; |
|
27 |
+ } |
|
28 |
+ |
|
29 |
+ public function __set($strKey, $varValue) |
|
30 |
+ { |
|
31 |
+ switch ($strKey) |
|
32 |
+ { |
|
33 |
+ case 'rows': |
|
34 |
+ $this->intRows = $varValue; |
|
35 |
+ break; |
|
36 |
+ |
|
37 |
+ case 'cols': |
|
38 |
+ $this->intCols = $varValue; |
|
39 |
+ break; |
|
40 |
+ default: |
|
41 |
+ parent::__set($strKey, $varValue); |
|
42 |
+ break; |
|
43 |
+ } |
|
44 |
+ } |
|
45 |
+ |
|
46 |
+ |
|
47 |
+ public function generate() |
|
48 |
+ { |
|
49 |
+ return $this->parse(); |
|
50 |
+ } |
|
51 |
+} |