| @@ -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 { |
| @@ -65,8 +66,31 @@ | ||
| 65 | 66 | // cannot leave the renderer with missing keys. |
| 66 | 67 | $styleValues = array_merge($styleValues, $proStyleValues); |
| 67 | 68 | } |
| 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 | + | |
| 69 | 93 | if ($context->isEmpty) { |
| 70 | 94 | // An "empty cell" renders as a bare, unstyled cell on the |
| 71 | 95 | // frontend: no content, and no background/border either, so it |
| 72 | 96 | // is indistinguishable from a cell that was never styled. |
| @@ -88,82 +112,82 @@ | ||
| 88 | 112 | |
| 89 | 113 | $isStickyFirstColCell = |
| 90 | 114 | $context->stickyFirstCol && $context->col === 0; |
| 91 | 115 | |
| 92 | - $styleParts = ['position:relative']; | |
| 116 | + $styleParts = ['position' => 'relative']; | |
| 93 | 117 | if ($styleValues['paddingTop'] !== '') { |
| 94 | - $styleParts[] = 'padding-top:' . $styleValues['paddingTop']; | |
| 118 | + $styleParts['padding-top'] = $styleValues['paddingTop']; | |
| 95 | 119 | } |
| 96 | 120 | if ($styleValues['paddingRight'] !== '') { |
| 97 | - $styleParts[] = 'padding-right:' . $styleValues['paddingRight']; | |
| 121 | + $styleParts['padding-right'] = $styleValues['paddingRight']; | |
| 98 | 122 | } |
| 99 | 123 | if ($styleValues['paddingBottom'] !== '') { |
| 100 | - $styleParts[] = 'padding-bottom:' . $styleValues['paddingBottom']; | |
| 124 | + $styleParts['padding-bottom'] = $styleValues['paddingBottom']; | |
| 101 | 125 | } |
| 102 | 126 | if ($styleValues['paddingLeft'] !== '') { |
| 103 | - $styleParts[] = 'padding-left:' . $styleValues['paddingLeft']; | |
| 127 | + $styleParts['padding-left'] = $styleValues['paddingLeft']; | |
| 104 | 128 | } |
| 105 | 129 | if ($styleValues['verticalAlign'] !== '') { |
| 106 | - $styleParts[] = 'vertical-align:' . $styleValues['verticalAlign']; | |
| 130 | + $styleParts['vertical-align'] = $styleValues['verticalAlign']; | |
| 107 | 131 | } |
| 108 | 132 | if ($styleValues['backgroundColor'] !== '') { |
| 109 | - $styleParts[] = 'background-color:' . $styleValues['backgroundColor']; | |
| 133 | + $styleParts['background-color'] = $styleValues['backgroundColor']; | |
| 110 | 134 | } |
| 111 | 135 | if ($styleValues['borderTop'] !== '') { |
| 112 | - $styleParts[] = 'border-top:' . $styleValues['borderTop']; | |
| 136 | + $styleParts['border-top'] = $styleValues['borderTop']; | |
| 113 | 137 | } |
| 114 | 138 | if ($styleValues['borderRight'] !== '') { |
| 115 | - $styleParts[] = 'border-right:' . $styleValues['borderRight']; | |
| 139 | + $styleParts['border-right'] = $styleValues['borderRight']; | |
| 116 | 140 | } |
| 117 | 141 | if ($styleValues['borderBottom'] !== '') { |
| 118 | - $styleParts[] = 'border-bottom:' . $styleValues['borderBottom']; | |
| 142 | + $styleParts['border-bottom'] = $styleValues['borderBottom']; | |
| 119 | 143 | } |
| 120 | 144 | if ($styleValues['borderLeft'] !== '') { |
| 121 | - $styleParts[] = 'border-left:' . $styleValues['borderLeft']; | |
| 145 | + $styleParts['border-left'] = $styleValues['borderLeft']; | |
| 122 | 146 | } |
| 123 | 147 | if ($styleValues['borderTopLeftRadius'] !== '') { |
| 124 | - $styleParts[] = 'border-top-left-radius:' . $styleValues['borderTopLeftRadius']; | |
| 148 | + $styleParts['border-top-left-radius'] = $styleValues['borderTopLeftRadius']; | |
| 125 | 149 | } |
| 126 | 150 | if ($styleValues['borderTopRightRadius'] !== '') { |
| 127 | - $styleParts[] = 'border-top-right-radius:' . $styleValues['borderTopRightRadius']; | |
| 151 | + $styleParts['border-top-right-radius'] = $styleValues['borderTopRightRadius']; | |
| 128 | 152 | } |
| 129 | 153 | if ($styleValues['borderBottomRightRadius'] !== '') { |
| 130 | - $styleParts[] = 'border-bottom-right-radius:' . $styleValues['borderBottomRightRadius']; | |
| 154 | + $styleParts['border-bottom-right-radius'] = $styleValues['borderBottomRightRadius']; | |
| 131 | 155 | } |
| 132 | 156 | if ($styleValues['borderBottomLeftRadius'] !== '') { |
| 133 | - $styleParts[] = 'border-bottom-left-radius:' . $styleValues['borderBottomLeftRadius']; | |
| 157 | + $styleParts['border-bottom-left-radius'] = $styleValues['borderBottomLeftRadius']; | |
| 134 | 158 | } |
| 135 | 159 | if ($context->colSpan === 1 && $context->width !== null && $context->width !== '') { |
| 136 | - $styleParts[] = 'width:' . $context->width; | |
| 137 | - $styleParts[] = 'min-width:' . $context->width; | |
| 160 | + $styleParts['width'] = $context->width; | |
| 161 | + $styleParts['min-width'] = $context->width; | |
| 138 | 162 | } |
| 139 | 163 | if ($context->rowSpan === 1 && $context->height !== null && $context->height !== '') { |
| 140 | - $styleParts[] = 'height:' . $context->height; | |
| 141 | - $styleParts[] = 'min-height:' . $context->height; | |
| 164 | + $styleParts['height'] = $context->height; | |
| 165 | + $styleParts['min-height'] = $context->height; | |
| 142 | 166 | } |
| 143 | 167 | |
| 144 | 168 | if ($isStickyHeaderCell) { |
| 145 | - $styleParts[] = 'position:sticky'; | |
| 146 | - $styleParts[] = 'top:0'; | |
| 147 | - $styleParts[] = $isStickyFirstColCell ? 'z-index:3' : 'z-index:2'; | |
| 169 | + $styleParts['position'] = 'sticky'; | |
| 170 | + $styleParts['top'] = '0'; | |
| 171 | + $styleParts['z-index'] = $isStickyFirstColCell ? '3' : '2'; | |
| 148 | 172 | |
| 149 | 173 | if ($styleValues['backgroundColor'] === '') { |
| 150 | - $styleParts[] = 'background-color:#fff'; | |
| 174 | + $styleParts['background-color'] = '#fff'; | |
| 151 | 175 | } |
| 152 | 176 | } |
| 153 | 177 | |
| 154 | 178 | if ($isStickyFirstColCell) { |
| 155 | 179 | if (!$isStickyHeaderCell) { |
| 156 | - $styleParts[] = 'position:sticky'; | |
| 157 | - $styleParts[] = 'z-index:1'; | |
| 180 | + $styleParts['position'] = 'sticky'; | |
| 181 | + $styleParts['z-index'] = '1'; | |
| 158 | 182 | } |
| 159 | - $styleParts[] = 'left:0'; | |
| 183 | + $styleParts['left'] = '0'; | |
| 160 | 184 | |
| 161 | 185 | if ( |
| 162 | 186 | !$isStickyHeaderCell && |
| 163 | 187 | $styleValues['backgroundColor'] === '' |
| 164 | 188 | ) { |
| 165 | - $styleParts[] = 'background-color:#fff'; | |
| 189 | + $styleParts['background-color'] = '#fff'; | |
| 166 | 190 | } |
| 167 | 191 | } |
| 168 | 192 | |
| 169 | 193 | $tag = $context->tag === 'th' ? 'th' : 'td'; |
| @@ -315,9 +339,9 @@ | ||
| 315 | 339 | > |
| 316 | 340 | ▲▼ |
| 317 | 341 | </span>" : ''; |
| 318 | 342 | |
| 319 | - $stylesStr = implode(';', $styleParts); | |
| 343 | + $stylesStr = generate_css_string($styleParts); | |
| 320 | 344 | |
| 321 | 345 | $attrsStr = ($tag === 'th' && $sortableType !== null) ? |
| 322 | 346 | "data-sortable='{$sortableType}' |
| 323 | 347 | role='button' |
| @@ -463,13 +487,11 @@ | ||
| 463 | 487 | && $cellStyleOverride['elementGap'] instanceof StringAttr) { |
| 464 | 488 | $styleValues['elementGap'] = $cellStyleOverride['elementGap']->asAttr(); |
| 465 | 489 | } |
| 466 | 490 | |
| 467 | - if (isset($cellStyleOverride['verticalAlign']) | |
| 468 | - && $cellStyleOverride['verticalAlign'] instanceof StringAttr) { | |
| 469 | - $verticalAlign = $cellStyleOverride['verticalAlign']->asAttr(); | |
| 470 | - $styleValues['verticalAlign'] = $verticalAlign; | |
| 471 | - } | |
| 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. | |
| 472 | 494 | |
| 473 | 495 | // Border is a pro attribute now (moved off this shared `styles` |
| 474 | 496 | // object, same as backgroundColor before it), resolved instead |
| 475 | 497 | // through the `tableberg/cell_styles` filter below — not here, or |