PluginProbe
Tableberg – Simple Gutenberg Table Block / 1.1.5
Tableberg – Simple Gutenberg Table Block v1.1.5
1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 trunk 0.0.2 0.2.1 0.3.2 0.3.3 0.4.1 0.5.0 0.5.1 0.5.2 0.5.3 0.5.4 0.5.5 0.5.6 0.5.7 All 42 releases
← All changes | renderer/Cell/CellRenderer.php +112 -51 1.0.11.1.5 View file →
@@ -8,8 +8,9 @@
8 8 use Tableberg\Renderer\ListEl\ListRenderer;
9 9 use Tableberg\Renderer\Text\TextRenderer;
10 10
11 11 use function apply_filters;
12 +use function Tableberg\Renderer\generate_css_string;
12 13 use function Tableberg\Renderer\getArrayOrNull;
13 14 use function Tableberg\Renderer\getStringOrNull;
14 15
15 16 class CellRenderer {
@@ -46,75 +47,150 @@
46 47 $context->cellStyleOverride,
47 48 $styleValues
48 49 );
49 50
51 + // Pro styling of a single cell goes through one filter rather than
52 + // one per property, so a new pro style needs no change here. Pro
53 + // gets the styles free resolved plus every attribute of the cell,
54 + // and returns the ones it wants rendered.
55 + //
56 + // Applied after the `styles` overrides rather than inside them: a
57 + // cell can carry a pro attribute without any `styles` at all.
58 + $proStyleValues = apply_filters(
59 + 'tableberg/cell_styles',
60 + $styleValues,
61 + $context->cellAttrs,
62 + $context
63 + );
64 + if (is_array($proStyleValues)) {
65 + // Merged, not replaced, so a filter that returns a partial set
66 + // cannot leave the renderer with missing keys.
67 + $styleValues = array_merge($styleValues, $proStyleValues);
68 + }
69 +
70 + // Table-wide Pro grid modes win over common and individual cell
71 + // borders. They render inner separators only; the separate table
72 + // border control owns the outside rectangle.
73 + if ($context->innerBorderType === 'row') {
74 + $styleValues['borderLeft'] = '';
75 + $styleValues['borderRight'] = '';
76 + if ($context->row === 0) {
77 + $styleValues['borderTop'] = '';
78 + }
79 + if ($context->row + $context->rowSpan >= $context->totalRows) {
80 + $styleValues['borderBottom'] = '';
81 + }
82 + } elseif ($context->innerBorderType === 'col') {
83 + $styleValues['borderTop'] = '';
84 + $styleValues['borderBottom'] = '';
85 + if ($context->col === 0) {
86 + $styleValues['borderLeft'] = '';
87 + }
88 + if ($context->col + $context->colSpan >= $context->totalCols) {
89 + $styleValues['borderRight'] = '';
90 + }
91 + }
92 +
93 + if ($context->isEmpty) {
94 + // An "empty cell" renders as a bare, unstyled cell on the
95 + // frontend: no content, and no background/border either, so it
96 + // is indistinguishable from a cell that was never styled.
97 + $styleValues['backgroundColor'] = '';
98 + $styleValues['borderTop'] = '';
99 + $styleValues['borderRight'] = '';
100 + $styleValues['borderBottom'] = '';
101 + $styleValues['borderLeft'] = '';
102 + $styleValues['borderTopLeftRadius'] = '';
103 + $styleValues['borderTopRightRadius'] = '';
104 + $styleValues['borderBottomRightRadius'] = '';
105 + $styleValues['borderBottomLeftRadius'] = '';
106 + }
107 +
50 108 $isStickyHeaderCell =
51 109 $context->stickyHeader &&
52 110 $context->row === 0 &&
53 111 $context->tag === 'th';
54 112
55 - $styleParts = ['position:relative'];
113 + $isStickyFirstColCell =
114 + $context->stickyFirstCol && $context->col === 0;
115 +
116 + $styleParts = ['position' => 'relative'];
56 117 if ($styleValues['paddingTop'] !== '') {
57 - $styleParts[] = 'padding-top:' . $styleValues['paddingTop'];
118 + $styleParts['padding-top'] = $styleValues['paddingTop'];
58 119 }
59 120 if ($styleValues['paddingRight'] !== '') {
60 - $styleParts[] = 'padding-right:' . $styleValues['paddingRight'];
121 + $styleParts['padding-right'] = $styleValues['paddingRight'];
61 122 }
62 123 if ($styleValues['paddingBottom'] !== '') {
63 - $styleParts[] = 'padding-bottom:' . $styleValues['paddingBottom'];
124 + $styleParts['padding-bottom'] = $styleValues['paddingBottom'];
64 125 }
65 126 if ($styleValues['paddingLeft'] !== '') {
66 - $styleParts[] = 'padding-left:' . $styleValues['paddingLeft'];
127 + $styleParts['padding-left'] = $styleValues['paddingLeft'];
67 128 }
68 129 if ($styleValues['verticalAlign'] !== '') {
69 - $styleParts[] = 'vertical-align:' . $styleValues['verticalAlign'];
130 + $styleParts['vertical-align'] = $styleValues['verticalAlign'];
70 131 }
71 132 if ($styleValues['backgroundColor'] !== '') {
72 - $styleParts[] = 'background-color:' . $styleValues['backgroundColor'];
133 + $styleParts['background-color'] = $styleValues['backgroundColor'];
73 134 }
74 135 if ($styleValues['borderTop'] !== '') {
75 - $styleParts[] = 'border-top:' . $styleValues['borderTop'];
136 + $styleParts['border-top'] = $styleValues['borderTop'];
76 137 }
77 138 if ($styleValues['borderRight'] !== '') {
78 - $styleParts[] = 'border-right:' . $styleValues['borderRight'];
139 + $styleParts['border-right'] = $styleValues['borderRight'];
79 140 }
80 141 if ($styleValues['borderBottom'] !== '') {
81 - $styleParts[] = 'border-bottom:' . $styleValues['borderBottom'];
142 + $styleParts['border-bottom'] = $styleValues['borderBottom'];
82 143 }
83 144 if ($styleValues['borderLeft'] !== '') {
84 - $styleParts[] = 'border-left:' . $styleValues['borderLeft'];
145 + $styleParts['border-left'] = $styleValues['borderLeft'];
85 146 }
86 147 if ($styleValues['borderTopLeftRadius'] !== '') {
87 - $styleParts[] = 'border-top-left-radius:' . $styleValues['borderTopLeftRadius'];
148 + $styleParts['border-top-left-radius'] = $styleValues['borderTopLeftRadius'];
88 149 }
89 150 if ($styleValues['borderTopRightRadius'] !== '') {
90 - $styleParts[] = 'border-top-right-radius:' . $styleValues['borderTopRightRadius'];
151 + $styleParts['border-top-right-radius'] = $styleValues['borderTopRightRadius'];
91 152 }
92 153 if ($styleValues['borderBottomRightRadius'] !== '') {
93 - $styleParts[] = 'border-bottom-right-radius:' . $styleValues['borderBottomRightRadius'];
154 + $styleParts['border-bottom-right-radius'] = $styleValues['borderBottomRightRadius'];
94 155 }
95 156 if ($styleValues['borderBottomLeftRadius'] !== '') {
96 - $styleParts[] = 'border-bottom-left-radius:' . $styleValues['borderBottomLeftRadius'];
157 + $styleParts['border-bottom-left-radius'] = $styleValues['borderBottomLeftRadius'];
97 158 }
98 159 if ($context->colSpan === 1 && $context->width !== null && $context->width !== '') {
99 - $styleParts[] = 'width:' . $context->width;
100 - $styleParts[] = 'min-width:' . $context->width;
160 + $styleParts['width'] = $context->width;
161 + $styleParts['min-width'] = $context->width;
101 162 }
102 163 if ($context->rowSpan === 1 && $context->height !== null && $context->height !== '') {
103 - $styleParts[] = 'height:' . $context->height;
104 - $styleParts[] = 'min-height:' . $context->height;
164 + $styleParts['height'] = $context->height;
165 + $styleParts['min-height'] = $context->height;
105 166 }
106 167
107 168 if ($isStickyHeaderCell) {
108 - $styleParts[] = 'position:sticky';
109 - $styleParts[] = 'top:0';
110 - $styleParts[] = 'z-index:2';
169 + $styleParts['position'] = 'sticky';
170 + $styleParts['top'] = '0';
171 + $styleParts['z-index'] = $isStickyFirstColCell ? '3' : '2';
111 172
112 173 if ($styleValues['backgroundColor'] === '') {
113 - $styleParts[] = 'background-color:#fff';
174 + $styleParts['background-color'] = '#fff';
114 175 }
115 176 }
116 177
178 + if ($isStickyFirstColCell) {
179 + if (!$isStickyHeaderCell) {
180 + $styleParts['position'] = 'sticky';
181 + $styleParts['z-index'] = '1';
182 + }
183 + $styleParts['left'] = '0';
184 +
185 + if (
186 + !$isStickyHeaderCell &&
187 + $styleValues['backgroundColor'] === ''
188 + ) {
189 + $styleParts['background-color'] = '#fff';
190 + }
191 + }
192 +
117 193 $tag = $context->tag === 'th' ? 'th' : 'td';
118 194 $sortableType = getStringOrNull($context->sortableType);
119 195
120 196 $buttonRenderer = new ButtonRenderer();
@@ -131,9 +207,10 @@
131 207 if (!is_object($element)) {
132 208 continue;
133 209 }
134 210
135 - $name = getStringOrNull($element->name->asText()) ?? 'unknown';
211 + $elementName = $element->name->asText();
212 + $name = getStringOrNull($elementName) ?? 'unknown';
136 213 $attributes = is_array($element->attributes)
137 214 ? $element->attributes
138 215 : [];
139 216
@@ -262,9 +339,9 @@
262 339 >
263 340 ▲▼
264 341 </span>" : '';
265 342
266 - $stylesStr = implode(';', $styleParts);
343 + $stylesStr = generate_css_string($styleParts);
267 344
268 345 $attrsStr = ($tag === 'th' && $sortableType !== null) ?
269 346 "data-sortable='{$sortableType}'
270 347 role='button'
@@ -345,9 +422,10 @@
345 422 if (!is_object($element)) {
346 423 continue;
347 424 }
348 425
349 - $name = getStringOrNull($element->name->asText()) ?? 'unknown';
426 + $elementName = $element->name->asText();
427 + $name = getStringOrNull($elementName) ?? 'unknown';
350 428 $attributes = is_array($element->attributes)
351 429 ? $element->attributes
352 430 : [];
353 431
@@ -392,13 +470,8 @@
392 470 $styleValues['paddingLeft'] = $overridePadding['left']->asAttr();
393 471 }
394 472 }
395 473
396 - if (isset($cellStyleOverride['backgroundColor'])
397 - && $cellStyleOverride['backgroundColor'] instanceof StringAttr) {
398 - $styleValues['backgroundColor'] = $cellStyleOverride['backgroundColor']->asAttr();
399 - }
400 -
401 474 if (isset($cellStyleOverride['orientation'])
402 475 && $cellStyleOverride['orientation'] instanceof StringAttr) {
403 476 $orientation = $cellStyleOverride['orientation']->asAttr();
404 477 $styleValues['orientation'] = $orientation;
@@ -414,29 +487,17 @@
414 487 && $cellStyleOverride['elementGap'] instanceof StringAttr) {
415 488 $styleValues['elementGap'] = $cellStyleOverride['elementGap']->asAttr();
416 489 }
417 490
418 - if (isset($cellStyleOverride['verticalAlign'])
419 - && $cellStyleOverride['verticalAlign'] instanceof StringAttr) {
420 - $verticalAlign = $cellStyleOverride['verticalAlign']->asAttr();
421 - $styleValues['verticalAlign'] = $verticalAlign;
422 - }
491 + // A cell's own vertical alignment is a pro feature, resolved through
492 + // the `tableberg/cell_styles` filter below. Free only applies the
493 + // table-wide default, so it can't be switched on without a licence.
423 494
424 - $overrideBorder = getArrayOrNull($cellStyleOverride['border']);
425 - if (is_array($overrideBorder)) {
426 - if (isset($overrideBorder['top']) && $overrideBorder['top'] instanceof StringAttr) {
427 - $styleValues['borderTop'] = $overrideBorder['top']->asAttr();
428 - }
429 - if (isset($overrideBorder['right']) && $overrideBorder['right'] instanceof StringAttr) {
430 - $styleValues['borderRight'] = $overrideBorder['right']->asAttr();
431 - }
432 - if (isset($overrideBorder['bottom']) && $overrideBorder['bottom'] instanceof StringAttr) {
433 - $styleValues['borderBottom'] = $overrideBorder['bottom']->asAttr();
434 - }
435 - if (isset($overrideBorder['left']) && $overrideBorder['left'] instanceof StringAttr) {
436 - $styleValues['borderLeft'] = $overrideBorder['left']->asAttr();
437 - }
438 - }
495 + // Border is a pro attribute now (moved off this shared `styles`
496 + // object, same as backgroundColor before it), resolved instead
497 + // through the `tableberg/cell_styles` filter below — not here, or
498 + // it would keep rendering a lapsed/legacy border regardless of
499 + // licence status.
439 500
440 501 $overrideBorderRadius = getArrayOrNull($cellStyleOverride['borderRadius']);
441 502 if (is_array($overrideBorderRadius)) {
442 503 if (isset($overrideBorderRadius['topLeft'])