PluginProbe
Tableberg – Simple Gutenberg Table Block / 1.2.0
Tableberg – Simple Gutenberg Table Block v1.2.0
1.2.0 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 All 43 releases
tableberg / src / migrate / v3-to-v4.ts

v3-to-v4.ts in Tableberg – Simple Gutenberg Table Block 1.2.0, at src/migrate/v3-to-v4.ts

139 lines 4.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { BlockInstance, createBlock } from "@wordpress/blocks";
2
3 import { Cell, CellKey, TablebergBlockAttrs } from "../attributes";
4
5 /**
6 * JS mirror of renderer/Migrations/TableBlockMigratorV3ToV4.php.
7 *
8 * Converts v3 (faux-block era) table attrs into the v4 native-blocks shape:
9 * slim attrs (no cells/rows) + a real block tree (rows -> cells -> elements).
10 * Used by the table block's deprecated entry, transforms, and the native
11 * edit's safety-net converter. Any v3 shim innerBlocks are discarded — the
12 * attrs are canonical.
13 */
14
15 export const ELEMENT_NAMES = [
16 "text",
17 "button",
18 "image",
19 "list",
20 "styled-list",
21 "icon",
22 "star-rating",
23 "custom-html",
24 ];
25
26 export function isV3OrOlder(attrs: Partial<TablebergBlockAttrs>): boolean {
27 return (attrs.version ?? 0) <= 3;
28 }
29
30 export function toV4Attrs(
31 attrs: Partial<TablebergBlockAttrs>
32 ): Partial<TablebergBlockAttrs> {
33 const slim: Record<string, unknown> = { ...attrs };
34 delete slim.cells;
35 delete slim.rows;
36 slim.version = 4;
37 return slim as Partial<TablebergBlockAttrs>;
38 }
39
40 /**
41 * Positions covered by a rowSpan/colSpan anchor (excluding the anchor).
42 */
43 function computeCoveredPositions(
44 cells: Partial<Record<CellKey, Cell>>,
45 rowsCount: number,
46 colsCount: number
47 ): Set<string> {
48 const covered = new Set<string>();
49
50 for (const [key, cell] of Object.entries(cells)) {
51 const span = cell?.span;
52 if (!span) {
53 continue;
54 }
55
56 const [row, col] = key.split(",").map(Number);
57 const rowSpan = Math.max(1, span.rowSpan || 1);
58 const colSpan = Math.max(1, span.colSpan || 1);
59
60 for (let dr = 0; dr < rowSpan; dr++) {
61 for (let dc = 0; dc < colSpan; dc++) {
62 if (dr === 0 && dc === 0) {
63 continue;
64 }
65 const r = row + dr;
66 const c = col + dc;
67 if (r >= rowsCount || c >= colsCount) {
68 continue;
69 }
70 covered.add(`${r},${c}`);
71 }
72 }
73 }
74
75 return covered;
76 }
77
78 function buildCellBlock(cell: Cell): BlockInstance {
79 // Every registered cell attribute must survive migration. `elements` is
80 // the only exception because it becomes the cell's inner block list.
81 const { elements = [], ...cellAttrs } = cell;
82
83 const elementBlocks: BlockInstance[] = [];
84 for (const element of elements) {
85 if (!element || !ELEMENT_NAMES.includes(element.name)) {
86 continue;
87 }
88
89 const elementAttrs: Record<string, unknown> = {
90 ...(element.attributes ?? {}),
91 };
92 if (element.bindings && Object.keys(element.bindings).length > 0) {
93 elementAttrs.bindings = element.bindings;
94 }
95
96 elementBlocks.push(
97 createBlock(`tableberg/${element.name}`, elementAttrs)
98 );
99 }
100
101 return createBlock("tableberg/cell", cellAttrs, elementBlocks);
102 }
103
104 /**
105 * Builds the v4 row-block tree from v3 attrs.
106 */
107 export function buildRowBlocksFromV3(
108 attrs: Partial<TablebergBlockAttrs>
109 ): BlockInstance[] {
110 const rowsCount = attrs.table?.rows ?? 0;
111 const colsCount = attrs.table?.cols ?? 0;
112 const cells = attrs.cells ?? {};
113 const rowConfigs = attrs.rows ?? [];
114
115 const covered = computeCoveredPositions(cells, rowsCount, colsCount);
116
117 const rowBlocks: BlockInstance[] = [];
118 for (let row = 0; row < rowsCount; row++) {
119 const cellBlocks: BlockInstance[] = [];
120
121 for (let col = 0; col < colsCount; col++) {
122 if (covered.has(`${row},${col}`)) {
123 continue;
124 }
125
126 const cell = cells[`${row},${col}` as CellKey] ?? {};
127 cellBlocks.push(buildCellBlock(cell));
128 }
129
130 // As with cells, rows can carry Pro-owned and future registered
131 // attributes that this migration must not need to name individually.
132 const rowAttrs = { ...(rowConfigs[row] ?? {}) };
133
134 rowBlocks.push(createBlock("tableberg/row", rowAttrs, cellBlocks));
135 }
136
137 return rowBlocks;
138 }
139