cf-pagetree-parser 1.0.8 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -958,6 +958,90 @@ function parseContentNode(element, parseChildren) {
958
958
  return node;
959
959
  }
960
960
 
961
+ /**
962
+ * Split rows whose columns' total span exceeds 12 into multiple rows.
963
+ * ClickFunnels renders all columns in a row side-by-side regardless of mdNum,
964
+ * so a row with e.g. 7 span-12 columns displays them all horizontally.
965
+ * This groups columns into batches that fit within 12 and creates separate rows.
966
+ */
967
+ function splitOverflowingRows(rows, sectionId) {
968
+ const result = [];
969
+
970
+ for (const row of rows) {
971
+ if (row.type !== 'RowContainer/V1' || !row.children || row.children.length <= 1) {
972
+ result.push(row);
973
+ continue;
974
+ }
975
+
976
+ const totalSpan = row.children.reduce((sum, col) => sum + (col.params?.mdNum || 12), 0);
977
+ if (totalSpan <= 12) {
978
+ result.push(row);
979
+ continue;
980
+ }
981
+
982
+ // Group columns so each group's total span ≤ 12
983
+ const groups = [];
984
+ let currentGroup = [];
985
+ let currentSpan = 0;
986
+
987
+ for (const col of row.children) {
988
+ const colSpan = col.params?.mdNum || 12;
989
+ if (currentSpan + colSpan > 12 && currentGroup.length > 0) {
990
+ groups.push(currentGroup);
991
+ currentGroup = [];
992
+ currentSpan = 0;
993
+ }
994
+ currentGroup.push(col);
995
+ currentSpan += colSpan;
996
+ }
997
+ if (currentGroup.length > 0) {
998
+ groups.push(currentGroup);
999
+ }
1000
+
1001
+ // First group stays in the original row
1002
+ row.children = groups[0].map((col, idx) => {
1003
+ col.parentId = row.id;
1004
+ col.fractionalIndex = generateFractionalIndex(idx);
1005
+ return col;
1006
+ });
1007
+ result.push(row);
1008
+
1009
+ // Additional groups get new RowContainers with the same styling
1010
+ for (let g = 1; g < groups.length; g++) {
1011
+ const extraId = generateId();
1012
+ const extraRow = {
1013
+ type: row.type,
1014
+ id: extraId,
1015
+ version: 0,
1016
+ parentId: sectionId,
1017
+ fractionalIndex: '',
1018
+ attrs: JSON.parse(JSON.stringify(row.attrs)),
1019
+ params: JSON.parse(JSON.stringify(row.params)),
1020
+ selectors: JSON.parse(JSON.stringify(row.selectors)),
1021
+ children: groups[g].map((col, idx) => {
1022
+ col.parentId = extraId;
1023
+ col.fractionalIndex = generateFractionalIndex(idx);
1024
+ return col;
1025
+ }),
1026
+ };
1027
+ // Continuation rows should not duplicate the original row's margin-top
1028
+ if (extraRow.attrs.style) {
1029
+ extraRow.attrs.style['margin-top'] = 0;
1030
+ }
1031
+ // Remove any element-id to avoid duplicate IDs in the page
1032
+ delete extraRow.attrs.id;
1033
+ result.push(extraRow);
1034
+ }
1035
+ }
1036
+
1037
+ // Re-index all rows with proper fractional indices
1038
+ result.forEach((row, idx) => {
1039
+ row.fractionalIndex = generateFractionalIndex(idx);
1040
+ });
1041
+
1042
+ return result;
1043
+ }
1044
+
961
1045
  /**
962
1046
  * Parse SectionContainer
963
1047
  */
@@ -1126,6 +1210,11 @@ function parseSectionContainer(element, parentId, index, parseChildren) {
1126
1210
  }
1127
1211
  });
1128
1212
 
1213
+ // Split rows whose column spans exceed 12 into multiple rows.
1214
+ // ClickFunnels renders all columns in a row side-by-side, so a row with
1215
+ // e.g. 7 span-12 columns would display them all horizontally instead of stacking.
1216
+ node.children = splitOverflowingRows(node.children, id);
1217
+
1129
1218
  return node;
1130
1219
  }
1131
1220
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cf-pagetree-parser",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "Parse FunnelWind HTML to ClickFunnels PageTree JSON",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -71,6 +71,90 @@ export function parseContentNode(element, parseChildren) {
71
71
  return node;
72
72
  }
73
73
 
74
+ /**
75
+ * Split rows whose columns' total span exceeds 12 into multiple rows.
76
+ * ClickFunnels renders all columns in a row side-by-side regardless of mdNum,
77
+ * so a row with e.g. 7 span-12 columns displays them all horizontally.
78
+ * This groups columns into batches that fit within 12 and creates separate rows.
79
+ */
80
+ function splitOverflowingRows(rows, sectionId) {
81
+ const result = [];
82
+
83
+ for (const row of rows) {
84
+ if (row.type !== 'RowContainer/V1' || !row.children || row.children.length <= 1) {
85
+ result.push(row);
86
+ continue;
87
+ }
88
+
89
+ const totalSpan = row.children.reduce((sum, col) => sum + (col.params?.mdNum || 12), 0);
90
+ if (totalSpan <= 12) {
91
+ result.push(row);
92
+ continue;
93
+ }
94
+
95
+ // Group columns so each group's total span ≤ 12
96
+ const groups = [];
97
+ let currentGroup = [];
98
+ let currentSpan = 0;
99
+
100
+ for (const col of row.children) {
101
+ const colSpan = col.params?.mdNum || 12;
102
+ if (currentSpan + colSpan > 12 && currentGroup.length > 0) {
103
+ groups.push(currentGroup);
104
+ currentGroup = [];
105
+ currentSpan = 0;
106
+ }
107
+ currentGroup.push(col);
108
+ currentSpan += colSpan;
109
+ }
110
+ if (currentGroup.length > 0) {
111
+ groups.push(currentGroup);
112
+ }
113
+
114
+ // First group stays in the original row
115
+ row.children = groups[0].map((col, idx) => {
116
+ col.parentId = row.id;
117
+ col.fractionalIndex = generateFractionalIndex(idx);
118
+ return col;
119
+ });
120
+ result.push(row);
121
+
122
+ // Additional groups get new RowContainers with the same styling
123
+ for (let g = 1; g < groups.length; g++) {
124
+ const extraId = generateId();
125
+ const extraRow = {
126
+ type: row.type,
127
+ id: extraId,
128
+ version: 0,
129
+ parentId: sectionId,
130
+ fractionalIndex: '',
131
+ attrs: JSON.parse(JSON.stringify(row.attrs)),
132
+ params: JSON.parse(JSON.stringify(row.params)),
133
+ selectors: JSON.parse(JSON.stringify(row.selectors)),
134
+ children: groups[g].map((col, idx) => {
135
+ col.parentId = extraId;
136
+ col.fractionalIndex = generateFractionalIndex(idx);
137
+ return col;
138
+ }),
139
+ };
140
+ // Continuation rows should not duplicate the original row's margin-top
141
+ if (extraRow.attrs.style) {
142
+ extraRow.attrs.style['margin-top'] = 0;
143
+ }
144
+ // Remove any element-id to avoid duplicate IDs in the page
145
+ delete extraRow.attrs.id;
146
+ result.push(extraRow);
147
+ }
148
+ }
149
+
150
+ // Re-index all rows with proper fractional indices
151
+ result.forEach((row, idx) => {
152
+ row.fractionalIndex = generateFractionalIndex(idx);
153
+ });
154
+
155
+ return result;
156
+ }
157
+
74
158
  /**
75
159
  * Parse SectionContainer
76
160
  */
@@ -239,6 +323,11 @@ export function parseSectionContainer(element, parentId, index, parseChildren) {
239
323
  }
240
324
  });
241
325
 
326
+ // Split rows whose column spans exceed 12 into multiple rows.
327
+ // ClickFunnels renders all columns in a row side-by-side, so a row with
328
+ // e.g. 7 span-12 columns would display them all horizontally instead of stacking.
329
+ node.children = splitOverflowingRows(node.children, id);
330
+
242
331
  return node;
243
332
  }
244
333