cf-pagetree-parser 1.0.4 → 1.0.6
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.
- package/README.md +14 -15
- package/dist/cf-pagetree-parser.js +85 -8
- package/package.json +1 -1
- package/src/index.js +2 -1
- package/src/parsers/button.js +4 -0
- package/src/parsers/form.js +25 -2
- package/src/parsers/interactive.js +16 -1
- package/src/parsers/list.js +10 -1
- package/src/parsers/media.js +16 -0
- package/src/parsers/text.js +12 -3
package/README.md
CHANGED
|
@@ -13,14 +13,13 @@ npm install cf-pagetree-parser
|
|
|
13
13
|
### ES Modules (Next.js, Node.js)
|
|
14
14
|
|
|
15
15
|
```javascript
|
|
16
|
-
import { parsePageTree
|
|
16
|
+
import { parsePageTree } from 'cf-pagetree-parser';
|
|
17
17
|
|
|
18
|
-
// Parse
|
|
19
|
-
const
|
|
20
|
-
const pageTree = parsePageTree(rootElement);
|
|
18
|
+
// Parse to PageTree JSON (automatically finds ContentNode)
|
|
19
|
+
const pageTree = parsePageTree();
|
|
21
20
|
|
|
22
|
-
//
|
|
23
|
-
|
|
21
|
+
// The result is ready for ClickFunnels import
|
|
22
|
+
console.log(JSON.stringify(pageTree, null, 2));
|
|
24
23
|
```
|
|
25
24
|
|
|
26
25
|
### Browser (Standalone Bundle)
|
|
@@ -29,7 +28,9 @@ const json = exportPageTreeJSON(rootElement, true);
|
|
|
29
28
|
<script src="dist/cf-pagetree-parser.js"></script>
|
|
30
29
|
<script>
|
|
31
30
|
const { parsePageTree } = CFPageTreeParser;
|
|
32
|
-
|
|
31
|
+
|
|
32
|
+
// Automatically finds ContentNode in the document
|
|
33
|
+
const pageTree = parsePageTree();
|
|
33
34
|
</script>
|
|
34
35
|
```
|
|
35
36
|
|
|
@@ -41,12 +42,10 @@ The `dist/cf-pagetree-parser.js` bundle can be used in sandboxed extension conte
|
|
|
41
42
|
|
|
42
43
|
### Main Functions
|
|
43
44
|
|
|
44
|
-
- `parsePageTree(rootElement)` - Parse DOM to PageTree object
|
|
45
|
-
- `
|
|
46
|
-
- `
|
|
47
|
-
- `
|
|
48
|
-
- `downloadPageTreeJSON(rootElement, filename?)` - Download JSON file
|
|
49
|
-
- `copyPageTreeToClipboard(rootElement)` - Copy to clipboard
|
|
45
|
+
- `parsePageTree(rootElement?)` - Parse DOM to PageTree object. If no element provided, automatically finds ContentNode.
|
|
46
|
+
- `exportPageTreeJSON(rootElement?, formatted?)` - Export as JSON string
|
|
47
|
+
- `downloadPageTree(filename?, rootElement?)` - Download JSON file
|
|
48
|
+
- `copyPageTreeToClipboard(rootElement?)` - Copy to clipboard
|
|
50
49
|
|
|
51
50
|
### Utilities
|
|
52
51
|
|
|
@@ -72,8 +71,8 @@ The parser extracts page-level settings from cf-page attributes:
|
|
|
72
71
|
| Attribute | Description |
|
|
73
72
|
|-----------|-------------|
|
|
74
73
|
| `font` | Page font family (e.g., "Poppins"). Applied to body-level styles. |
|
|
75
|
-
| `
|
|
76
|
-
| `text-color` |
|
|
74
|
+
| `color` | Default text color for all elements (default: #334155) |
|
|
75
|
+
| `text-color` | Alias for `color` |
|
|
77
76
|
| `link-color` | Default link color (default: #3b82f6) |
|
|
78
77
|
| `font-weight` | Default font weight |
|
|
79
78
|
| `css` | Custom CSS (URL-encoded) |
|
|
@@ -1653,10 +1653,19 @@ function parseTextElement(
|
|
|
1653
1653
|
? parseFontFamily(fontAttr)
|
|
1654
1654
|
: parseFontFamily(textStyles["font-family"]);
|
|
1655
1655
|
|
|
1656
|
+
// Get color: element data-color > inline style > page color > default
|
|
1656
1657
|
const colorAttr = element.getAttribute("data-color");
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1658
|
+
let color;
|
|
1659
|
+
if (colorAttr) {
|
|
1660
|
+
color = normalizeColor(colorAttr);
|
|
1661
|
+
} else if (textStyles.color) {
|
|
1662
|
+
color = normalizeColor(textStyles.color);
|
|
1663
|
+
} else {
|
|
1664
|
+
// Fall back to page-level color from ContentNode
|
|
1665
|
+
const contentNode = element.closest('[data-type="ContentNode"]');
|
|
1666
|
+
const pageColor = contentNode?.getAttribute("data-color") || contentNode?.getAttribute("data-text-color");
|
|
1667
|
+
color = pageColor ? normalizeColor(pageColor) : "#000000";
|
|
1668
|
+
}
|
|
1660
1669
|
|
|
1661
1670
|
const alignAttr = element.getAttribute("data-align");
|
|
1662
1671
|
const textAlign = alignAttr || parseTextAlign(textStyles["text-align"]);
|
|
@@ -1872,6 +1881,9 @@ function parseButton(element, parentId, index) {
|
|
|
1872
1881
|
const mainTextId = generateId();
|
|
1873
1882
|
const subTextId = generateId();
|
|
1874
1883
|
|
|
1884
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
1885
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
1886
|
+
|
|
1875
1887
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
1876
1888
|
const spacing = parseSpacing(wrapperStyles);
|
|
1877
1889
|
|
|
@@ -1994,6 +2006,7 @@ function parseButton(element, parentId, index) {
|
|
|
1994
2006
|
parentId,
|
|
1995
2007
|
fractionalIndex: generateFractionalIndex(index),
|
|
1996
2008
|
attrs: {
|
|
2009
|
+
...(elementId ? { id: elementId } : {}),
|
|
1997
2010
|
style: {
|
|
1998
2011
|
'text-align': textAlign,
|
|
1999
2012
|
},
|
|
@@ -2170,6 +2183,9 @@ function parseButton(element, parentId, index) {
|
|
|
2170
2183
|
function parseImage(element, parentId, index) {
|
|
2171
2184
|
const id = generateId();
|
|
2172
2185
|
|
|
2186
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
2187
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
2188
|
+
|
|
2173
2189
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
2174
2190
|
const spacing = parseSpacing(wrapperStyles);
|
|
2175
2191
|
const textAlign = parseTextAlign(wrapperStyles['text-align']);
|
|
@@ -2198,6 +2214,7 @@ function parseImage(element, parentId, index) {
|
|
|
2198
2214
|
parentId,
|
|
2199
2215
|
fractionalIndex: generateFractionalIndex(index),
|
|
2200
2216
|
attrs: {
|
|
2217
|
+
...(elementId ? { id: elementId } : {}),
|
|
2201
2218
|
alt,
|
|
2202
2219
|
style: {
|
|
2203
2220
|
'text-align': textAlign,
|
|
@@ -2266,6 +2283,9 @@ function parseImage(element, parentId, index) {
|
|
|
2266
2283
|
function parseIcon(element, parentId, index) {
|
|
2267
2284
|
const id = generateId();
|
|
2268
2285
|
|
|
2286
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
2287
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
2288
|
+
|
|
2269
2289
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
2270
2290
|
const spacing = parseSpacing(wrapperStyles);
|
|
2271
2291
|
const textAlign = parseTextAlign(wrapperStyles['text-align']);
|
|
@@ -2301,6 +2321,7 @@ function parseIcon(element, parentId, index) {
|
|
|
2301
2321
|
parentId,
|
|
2302
2322
|
fractionalIndex: generateFractionalIndex(index),
|
|
2303
2323
|
attrs: {
|
|
2324
|
+
...(elementId ? { id: elementId } : {}),
|
|
2304
2325
|
style: {},
|
|
2305
2326
|
...animationAttrs,
|
|
2306
2327
|
},
|
|
@@ -2349,6 +2370,9 @@ function parseIcon(element, parentId, index) {
|
|
|
2349
2370
|
function parseVideo(element, parentId, index) {
|
|
2350
2371
|
const id = generateId();
|
|
2351
2372
|
|
|
2373
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
2374
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
2375
|
+
|
|
2352
2376
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
2353
2377
|
const spacing = parseSpacing(wrapperStyles);
|
|
2354
2378
|
|
|
@@ -2372,6 +2396,7 @@ function parseVideo(element, parentId, index) {
|
|
|
2372
2396
|
parentId,
|
|
2373
2397
|
fractionalIndex: generateFractionalIndex(index),
|
|
2374
2398
|
attrs: {
|
|
2399
|
+
...(elementId ? { id: elementId } : {}),
|
|
2375
2400
|
'data-video-type': videoType,
|
|
2376
2401
|
'data-skip-background-settings': background.color ? 'false' : 'true',
|
|
2377
2402
|
'data-skip-shadow-settings': shadow ? 'false' : 'true',
|
|
@@ -2423,6 +2448,9 @@ function parseVideo(element, parentId, index) {
|
|
|
2423
2448
|
function parseDivider(element, parentId, index) {
|
|
2424
2449
|
const id = generateId();
|
|
2425
2450
|
|
|
2451
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
2452
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
2453
|
+
|
|
2426
2454
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
2427
2455
|
const spacing = parseSpacing(wrapperStyles);
|
|
2428
2456
|
|
|
@@ -2468,6 +2496,7 @@ function parseDivider(element, parentId, index) {
|
|
|
2468
2496
|
parentId,
|
|
2469
2497
|
fractionalIndex: generateFractionalIndex(index),
|
|
2470
2498
|
attrs: {
|
|
2499
|
+
...(elementId ? { id: elementId } : {}),
|
|
2471
2500
|
style: {},
|
|
2472
2501
|
},
|
|
2473
2502
|
params: {
|
|
@@ -2527,6 +2556,9 @@ function parseDivider(element, parentId, index) {
|
|
|
2527
2556
|
function parseInput(element, parentId, index) {
|
|
2528
2557
|
const id = generateId();
|
|
2529
2558
|
|
|
2559
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
2560
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
2561
|
+
|
|
2530
2562
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
2531
2563
|
const spacing = parseSpacing(wrapperStyles);
|
|
2532
2564
|
|
|
@@ -2569,6 +2601,7 @@ function parseInput(element, parentId, index) {
|
|
|
2569
2601
|
parentId,
|
|
2570
2602
|
fractionalIndex: generateFractionalIndex(index),
|
|
2571
2603
|
attrs: {
|
|
2604
|
+
...(elementId ? { id: elementId } : {}),
|
|
2572
2605
|
'data-skip-shadow-settings': shadow ? 'false' : 'true',
|
|
2573
2606
|
type: inputType === 'phone_number' ? 'tel' : (inputType === 'email' ? 'email' : 'text'),
|
|
2574
2607
|
style: {
|
|
@@ -2687,6 +2720,9 @@ function parseInput(element, parentId, index) {
|
|
|
2687
2720
|
function parseTextArea(element, parentId, index) {
|
|
2688
2721
|
const id = generateId();
|
|
2689
2722
|
|
|
2723
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
2724
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
2725
|
+
|
|
2690
2726
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
2691
2727
|
const spacing = parseSpacing(wrapperStyles);
|
|
2692
2728
|
|
|
@@ -2728,6 +2764,7 @@ function parseTextArea(element, parentId, index) {
|
|
|
2728
2764
|
parentId,
|
|
2729
2765
|
fractionalIndex: generateFractionalIndex(index),
|
|
2730
2766
|
attrs: {
|
|
2767
|
+
...(elementId ? { id: elementId } : {}),
|
|
2731
2768
|
'data-skip-shadow-settings': shadow ? 'false' : 'true',
|
|
2732
2769
|
style: {
|
|
2733
2770
|
width,
|
|
@@ -2844,6 +2881,9 @@ function parseTextArea(element, parentId, index) {
|
|
|
2844
2881
|
function parseSelectBox(element, parentId, index) {
|
|
2845
2882
|
const id = generateId();
|
|
2846
2883
|
|
|
2884
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
2885
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
2886
|
+
|
|
2847
2887
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
2848
2888
|
const spacing = parseSpacing(wrapperStyles);
|
|
2849
2889
|
|
|
@@ -2912,6 +2952,7 @@ function parseSelectBox(element, parentId, index) {
|
|
|
2912
2952
|
parentId,
|
|
2913
2953
|
fractionalIndex: generateFractionalIndex(index),
|
|
2914
2954
|
attrs: {
|
|
2955
|
+
...(elementId ? { id: elementId } : {}),
|
|
2915
2956
|
style: {
|
|
2916
2957
|
width,
|
|
2917
2958
|
'margin-top': marginTop.value,
|
|
@@ -3017,6 +3058,9 @@ function parseSelectBox(element, parentId, index) {
|
|
|
3017
3058
|
function parseCheckbox(element, parentId, index) {
|
|
3018
3059
|
const id = generateId();
|
|
3019
3060
|
|
|
3061
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
3062
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
3063
|
+
|
|
3020
3064
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
3021
3065
|
const spacing = parseSpacing(wrapperStyles);
|
|
3022
3066
|
|
|
@@ -3040,9 +3084,16 @@ function parseCheckbox(element, parentId, index) {
|
|
|
3040
3084
|
const boxBorderColor = boxBorderMatch ? normalizeColor(boxBorderMatch[2]) : 'rgb(229, 231, 235)';
|
|
3041
3085
|
const boxBorderRadius = parseBorderRadius(boxStyles);
|
|
3042
3086
|
|
|
3043
|
-
// Label text styling
|
|
3087
|
+
// Label text styling - inherit page color if not set
|
|
3044
3088
|
const textStyles = textSpan ? parseInlineStyle(textSpan.getAttribute('style') || '') : {};
|
|
3045
|
-
|
|
3089
|
+
let labelColor;
|
|
3090
|
+
if (textStyles.color) {
|
|
3091
|
+
labelColor = normalizeColor(textStyles.color);
|
|
3092
|
+
} else {
|
|
3093
|
+
const contentNode = element.closest('[data-type="ContentNode"]');
|
|
3094
|
+
const pageColor = contentNode?.getAttribute("data-color") || contentNode?.getAttribute("data-text-color");
|
|
3095
|
+
labelColor = pageColor ? normalizeColor(pageColor) : '#334155';
|
|
3096
|
+
}
|
|
3046
3097
|
const labelFontSize = parseValueWithUnit(textStyles['font-size'] || '16px');
|
|
3047
3098
|
|
|
3048
3099
|
// Gap between checkbox and label
|
|
@@ -3056,6 +3107,7 @@ function parseCheckbox(element, parentId, index) {
|
|
|
3056
3107
|
parentId,
|
|
3057
3108
|
fractionalIndex: generateFractionalIndex(index),
|
|
3058
3109
|
attrs: {
|
|
3110
|
+
...(elementId ? { id: elementId } : {}),
|
|
3059
3111
|
style: {},
|
|
3060
3112
|
},
|
|
3061
3113
|
params: {
|
|
@@ -3168,6 +3220,9 @@ function parseBulletList(element, parentId, index) {
|
|
|
3168
3220
|
const id = generateId();
|
|
3169
3221
|
const contentEditableId = generateId();
|
|
3170
3222
|
|
|
3223
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
3224
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
3225
|
+
|
|
3171
3226
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
3172
3227
|
const spacing = parseSpacing(wrapperStyles);
|
|
3173
3228
|
|
|
@@ -3190,12 +3245,17 @@ function parseBulletList(element, parentId, index) {
|
|
|
3190
3245
|
// Find list items
|
|
3191
3246
|
const items = ul ? ul.querySelectorAll('li') : [];
|
|
3192
3247
|
|
|
3248
|
+
// Get page-level color from ContentNode for fallback
|
|
3249
|
+
const contentNode = element.closest('[data-type="ContentNode"]');
|
|
3250
|
+
const pageColor = contentNode?.getAttribute("data-color") || contentNode?.getAttribute("data-text-color");
|
|
3251
|
+
const defaultTextColor = pageColor ? normalizeColor(pageColor) : '#334155';
|
|
3252
|
+
|
|
3193
3253
|
// Initialize with defaults, will be overridden by data attrs or inline styles
|
|
3194
3254
|
let iconClass = 'fas fa-check fa_icon';
|
|
3195
3255
|
let iconColor = '#10b981';
|
|
3196
3256
|
let iconMarginRight = 12;
|
|
3197
3257
|
let iconSize = null;
|
|
3198
|
-
let textColor =
|
|
3258
|
+
let textColor = defaultTextColor;
|
|
3199
3259
|
let textSize = null;
|
|
3200
3260
|
let justifyContent = 'flex-start';
|
|
3201
3261
|
|
|
@@ -3295,6 +3355,7 @@ function parseBulletList(element, parentId, index) {
|
|
|
3295
3355
|
parentId,
|
|
3296
3356
|
fractionalIndex: generateFractionalIndex(index),
|
|
3297
3357
|
attrs: {
|
|
3358
|
+
...(elementId ? { id: elementId } : {}),
|
|
3298
3359
|
style: {},
|
|
3299
3360
|
},
|
|
3300
3361
|
params: {
|
|
@@ -3513,6 +3574,9 @@ function parseBulletList(element, parentId, index) {
|
|
|
3513
3574
|
function parseProgressBar(element, parentId, index) {
|
|
3514
3575
|
const id = generateId();
|
|
3515
3576
|
|
|
3577
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
3578
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
3579
|
+
|
|
3516
3580
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
3517
3581
|
const spacing = parseSpacing(wrapperStyles);
|
|
3518
3582
|
|
|
@@ -3556,6 +3620,7 @@ function parseProgressBar(element, parentId, index) {
|
|
|
3556
3620
|
parentId,
|
|
3557
3621
|
fractionalIndex: generateFractionalIndex(index),
|
|
3558
3622
|
attrs: {
|
|
3623
|
+
...(elementId ? { id: elementId } : {}),
|
|
3559
3624
|
style: {},
|
|
3560
3625
|
},
|
|
3561
3626
|
params: {
|
|
@@ -3635,6 +3700,9 @@ function parseProgressBar(element, parentId, index) {
|
|
|
3635
3700
|
function parseVideoPopup(element, parentId, index) {
|
|
3636
3701
|
const id = generateId();
|
|
3637
3702
|
|
|
3703
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
3704
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
3705
|
+
|
|
3638
3706
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
3639
3707
|
const spacing = parseSpacing(wrapperStyles);
|
|
3640
3708
|
const textAlign = parseTextAlign(wrapperStyles['text-align']);
|
|
@@ -3673,6 +3741,7 @@ function parseVideoPopup(element, parentId, index) {
|
|
|
3673
3741
|
parentId,
|
|
3674
3742
|
fractionalIndex: generateFractionalIndex(index),
|
|
3675
3743
|
attrs: {
|
|
3744
|
+
...(elementId ? { id: elementId } : {}),
|
|
3676
3745
|
alt: alt || 'Video thumbnail',
|
|
3677
3746
|
},
|
|
3678
3747
|
params: {
|
|
@@ -3750,6 +3819,9 @@ function parseVideoPopup(element, parentId, index) {
|
|
|
3750
3819
|
function parseCountdown(element, parentId, index) {
|
|
3751
3820
|
const id = generateId();
|
|
3752
3821
|
|
|
3822
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
3823
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
3824
|
+
|
|
3753
3825
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
3754
3826
|
const spacing = parseSpacing(wrapperStyles);
|
|
3755
3827
|
|
|
@@ -3823,6 +3895,10 @@ function parseCountdown(element, parentId, index) {
|
|
|
3823
3895
|
version: 0,
|
|
3824
3896
|
parentId,
|
|
3825
3897
|
fractionalIndex: generateFractionalIndex(index),
|
|
3898
|
+
attrs: {
|
|
3899
|
+
...(elementId ? { id: elementId } : {}),
|
|
3900
|
+
style: {},
|
|
3901
|
+
},
|
|
3826
3902
|
params: {
|
|
3827
3903
|
type: 'countdown',
|
|
3828
3904
|
countdown_opts: {
|
|
@@ -3947,7 +4023,7 @@ function parseCountdown(element, parentId, index) {
|
|
|
3947
4023
|
|
|
3948
4024
|
// Apply spacing
|
|
3949
4025
|
const { attrs: spacingAttrs, params: spacingParams } = spacingToAttrsAndParams(spacing);
|
|
3950
|
-
Object.assign(node.attrs
|
|
4026
|
+
Object.assign(node.attrs.style, spacingAttrs.style);
|
|
3951
4027
|
Object.assign(node.params, spacingParams);
|
|
3952
4028
|
|
|
3953
4029
|
// Apply border to amount container
|
|
@@ -4467,7 +4543,8 @@ function parsePageTree(rootElement = null) {
|
|
|
4467
4543
|
}
|
|
4468
4544
|
|
|
4469
4545
|
// Extract page settings from data attributes
|
|
4470
|
-
|
|
4546
|
+
// Support both 'color' (simple) and 'text-color' (explicit) for page text color
|
|
4547
|
+
const textColorRaw = rootElement.getAttribute("data-color") || rootElement.getAttribute("data-text-color") || "#334155";
|
|
4471
4548
|
const linkColorRaw = rootElement.getAttribute("data-link-color") || "#3b82f6";
|
|
4472
4549
|
const textColor = normalizeColor(textColorRaw);
|
|
4473
4550
|
const linkColor = normalizeColor(linkColorRaw);
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -221,7 +221,8 @@ export function parsePageTree(rootElement = null) {
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
// Extract page settings from data attributes
|
|
224
|
-
|
|
224
|
+
// Support both 'color' (simple) and 'text-color' (explicit) for page text color
|
|
225
|
+
const textColorRaw = rootElement.getAttribute("data-color") || rootElement.getAttribute("data-text-color") || "#334155";
|
|
225
226
|
const linkColorRaw = rootElement.getAttribute("data-link-color") || "#3b82f6";
|
|
226
227
|
const textColor = normalizeColor(textColorRaw);
|
|
227
228
|
const linkColor = normalizeColor(linkColorRaw);
|
package/src/parsers/button.js
CHANGED
|
@@ -40,6 +40,9 @@ export function parseButton(element, parentId, index) {
|
|
|
40
40
|
const mainTextId = generateId();
|
|
41
41
|
const subTextId = generateId();
|
|
42
42
|
|
|
43
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
44
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
45
|
+
|
|
43
46
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
44
47
|
const spacing = parseSpacing(wrapperStyles);
|
|
45
48
|
|
|
@@ -162,6 +165,7 @@ export function parseButton(element, parentId, index) {
|
|
|
162
165
|
parentId,
|
|
163
166
|
fractionalIndex: generateFractionalIndex(index),
|
|
164
167
|
attrs: {
|
|
168
|
+
...(elementId ? { id: elementId } : {}),
|
|
165
169
|
style: {
|
|
166
170
|
'text-align': textAlign,
|
|
167
171
|
},
|
package/src/parsers/form.js
CHANGED
|
@@ -34,6 +34,9 @@ import {
|
|
|
34
34
|
export function parseInput(element, parentId, index) {
|
|
35
35
|
const id = generateId();
|
|
36
36
|
|
|
37
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
38
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
39
|
+
|
|
37
40
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
38
41
|
const spacing = parseSpacing(wrapperStyles);
|
|
39
42
|
|
|
@@ -76,6 +79,7 @@ export function parseInput(element, parentId, index) {
|
|
|
76
79
|
parentId,
|
|
77
80
|
fractionalIndex: generateFractionalIndex(index),
|
|
78
81
|
attrs: {
|
|
82
|
+
...(elementId ? { id: elementId } : {}),
|
|
79
83
|
'data-skip-shadow-settings': shadow ? 'false' : 'true',
|
|
80
84
|
type: inputType === 'phone_number' ? 'tel' : (inputType === 'email' ? 'email' : 'text'),
|
|
81
85
|
style: {
|
|
@@ -194,6 +198,9 @@ export function parseInput(element, parentId, index) {
|
|
|
194
198
|
export function parseTextArea(element, parentId, index) {
|
|
195
199
|
const id = generateId();
|
|
196
200
|
|
|
201
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
202
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
203
|
+
|
|
197
204
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
198
205
|
const spacing = parseSpacing(wrapperStyles);
|
|
199
206
|
|
|
@@ -235,6 +242,7 @@ export function parseTextArea(element, parentId, index) {
|
|
|
235
242
|
parentId,
|
|
236
243
|
fractionalIndex: generateFractionalIndex(index),
|
|
237
244
|
attrs: {
|
|
245
|
+
...(elementId ? { id: elementId } : {}),
|
|
238
246
|
'data-skip-shadow-settings': shadow ? 'false' : 'true',
|
|
239
247
|
style: {
|
|
240
248
|
width,
|
|
@@ -351,6 +359,9 @@ export function parseTextArea(element, parentId, index) {
|
|
|
351
359
|
export function parseSelectBox(element, parentId, index) {
|
|
352
360
|
const id = generateId();
|
|
353
361
|
|
|
362
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
363
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
364
|
+
|
|
354
365
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
355
366
|
const spacing = parseSpacing(wrapperStyles);
|
|
356
367
|
|
|
@@ -419,6 +430,7 @@ export function parseSelectBox(element, parentId, index) {
|
|
|
419
430
|
parentId,
|
|
420
431
|
fractionalIndex: generateFractionalIndex(index),
|
|
421
432
|
attrs: {
|
|
433
|
+
...(elementId ? { id: elementId } : {}),
|
|
422
434
|
style: {
|
|
423
435
|
width,
|
|
424
436
|
'margin-top': marginTop.value,
|
|
@@ -524,6 +536,9 @@ export function parseSelectBox(element, parentId, index) {
|
|
|
524
536
|
export function parseCheckbox(element, parentId, index) {
|
|
525
537
|
const id = generateId();
|
|
526
538
|
|
|
539
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
540
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
541
|
+
|
|
527
542
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
528
543
|
const spacing = parseSpacing(wrapperStyles);
|
|
529
544
|
|
|
@@ -547,9 +562,16 @@ export function parseCheckbox(element, parentId, index) {
|
|
|
547
562
|
const boxBorderColor = boxBorderMatch ? normalizeColor(boxBorderMatch[2]) : 'rgb(229, 231, 235)';
|
|
548
563
|
const boxBorderRadius = parseBorderRadius(boxStyles);
|
|
549
564
|
|
|
550
|
-
// Label text styling
|
|
565
|
+
// Label text styling - inherit page color if not set
|
|
551
566
|
const textStyles = textSpan ? parseInlineStyle(textSpan.getAttribute('style') || '') : {};
|
|
552
|
-
|
|
567
|
+
let labelColor;
|
|
568
|
+
if (textStyles.color) {
|
|
569
|
+
labelColor = normalizeColor(textStyles.color);
|
|
570
|
+
} else {
|
|
571
|
+
const contentNode = element.closest('[data-type="ContentNode"]');
|
|
572
|
+
const pageColor = contentNode?.getAttribute("data-color") || contentNode?.getAttribute("data-text-color");
|
|
573
|
+
labelColor = pageColor ? normalizeColor(pageColor) : '#334155';
|
|
574
|
+
}
|
|
553
575
|
const labelFontSize = parseValueWithUnit(textStyles['font-size'] || '16px');
|
|
554
576
|
|
|
555
577
|
// Gap between checkbox and label
|
|
@@ -563,6 +585,7 @@ export function parseCheckbox(element, parentId, index) {
|
|
|
563
585
|
parentId,
|
|
564
586
|
fractionalIndex: generateFractionalIndex(index),
|
|
565
587
|
attrs: {
|
|
588
|
+
...(elementId ? { id: elementId } : {}),
|
|
566
589
|
style: {},
|
|
567
590
|
},
|
|
568
591
|
params: {
|
|
@@ -33,6 +33,9 @@ import {
|
|
|
33
33
|
export function parseProgressBar(element, parentId, index) {
|
|
34
34
|
const id = generateId();
|
|
35
35
|
|
|
36
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
37
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
38
|
+
|
|
36
39
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
37
40
|
const spacing = parseSpacing(wrapperStyles);
|
|
38
41
|
|
|
@@ -76,6 +79,7 @@ export function parseProgressBar(element, parentId, index) {
|
|
|
76
79
|
parentId,
|
|
77
80
|
fractionalIndex: generateFractionalIndex(index),
|
|
78
81
|
attrs: {
|
|
82
|
+
...(elementId ? { id: elementId } : {}),
|
|
79
83
|
style: {},
|
|
80
84
|
},
|
|
81
85
|
params: {
|
|
@@ -155,6 +159,9 @@ export function parseProgressBar(element, parentId, index) {
|
|
|
155
159
|
export function parseVideoPopup(element, parentId, index) {
|
|
156
160
|
const id = generateId();
|
|
157
161
|
|
|
162
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
163
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
164
|
+
|
|
158
165
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
159
166
|
const spacing = parseSpacing(wrapperStyles);
|
|
160
167
|
const textAlign = parseTextAlign(wrapperStyles['text-align']);
|
|
@@ -193,6 +200,7 @@ export function parseVideoPopup(element, parentId, index) {
|
|
|
193
200
|
parentId,
|
|
194
201
|
fractionalIndex: generateFractionalIndex(index),
|
|
195
202
|
attrs: {
|
|
203
|
+
...(elementId ? { id: elementId } : {}),
|
|
196
204
|
alt: alt || 'Video thumbnail',
|
|
197
205
|
},
|
|
198
206
|
params: {
|
|
@@ -270,6 +278,9 @@ export function parseVideoPopup(element, parentId, index) {
|
|
|
270
278
|
export function parseCountdown(element, parentId, index) {
|
|
271
279
|
const id = generateId();
|
|
272
280
|
|
|
281
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
282
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
283
|
+
|
|
273
284
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
274
285
|
const spacing = parseSpacing(wrapperStyles);
|
|
275
286
|
|
|
@@ -343,6 +354,10 @@ export function parseCountdown(element, parentId, index) {
|
|
|
343
354
|
version: 0,
|
|
344
355
|
parentId,
|
|
345
356
|
fractionalIndex: generateFractionalIndex(index),
|
|
357
|
+
attrs: {
|
|
358
|
+
...(elementId ? { id: elementId } : {}),
|
|
359
|
+
style: {},
|
|
360
|
+
},
|
|
346
361
|
params: {
|
|
347
362
|
type: 'countdown',
|
|
348
363
|
countdown_opts: {
|
|
@@ -467,7 +482,7 @@ export function parseCountdown(element, parentId, index) {
|
|
|
467
482
|
|
|
468
483
|
// Apply spacing
|
|
469
484
|
const { attrs: spacingAttrs, params: spacingParams } = spacingToAttrsAndParams(spacing);
|
|
470
|
-
Object.assign(node.attrs
|
|
485
|
+
Object.assign(node.attrs.style, spacingAttrs.style);
|
|
471
486
|
Object.assign(node.params, spacingParams);
|
|
472
487
|
|
|
473
488
|
// Apply border to amount container
|
package/src/parsers/list.js
CHANGED
|
@@ -29,6 +29,9 @@ export function parseBulletList(element, parentId, index) {
|
|
|
29
29
|
const id = generateId();
|
|
30
30
|
const contentEditableId = generateId();
|
|
31
31
|
|
|
32
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
33
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
34
|
+
|
|
32
35
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
33
36
|
const spacing = parseSpacing(wrapperStyles);
|
|
34
37
|
|
|
@@ -51,12 +54,17 @@ export function parseBulletList(element, parentId, index) {
|
|
|
51
54
|
// Find list items
|
|
52
55
|
const items = ul ? ul.querySelectorAll('li') : [];
|
|
53
56
|
|
|
57
|
+
// Get page-level color from ContentNode for fallback
|
|
58
|
+
const contentNode = element.closest('[data-type="ContentNode"]');
|
|
59
|
+
const pageColor = contentNode?.getAttribute("data-color") || contentNode?.getAttribute("data-text-color");
|
|
60
|
+
const defaultTextColor = pageColor ? normalizeColor(pageColor) : '#334155';
|
|
61
|
+
|
|
54
62
|
// Initialize with defaults, will be overridden by data attrs or inline styles
|
|
55
63
|
let iconClass = 'fas fa-check fa_icon';
|
|
56
64
|
let iconColor = '#10b981';
|
|
57
65
|
let iconMarginRight = 12;
|
|
58
66
|
let iconSize = null;
|
|
59
|
-
let textColor =
|
|
67
|
+
let textColor = defaultTextColor;
|
|
60
68
|
let textSize = null;
|
|
61
69
|
let justifyContent = 'flex-start';
|
|
62
70
|
|
|
@@ -156,6 +164,7 @@ export function parseBulletList(element, parentId, index) {
|
|
|
156
164
|
parentId,
|
|
157
165
|
fractionalIndex: generateFractionalIndex(index),
|
|
158
166
|
attrs: {
|
|
167
|
+
...(elementId ? { id: elementId } : {}),
|
|
159
168
|
style: {},
|
|
160
169
|
},
|
|
161
170
|
params: {
|
package/src/parsers/media.js
CHANGED
|
@@ -35,6 +35,9 @@ import {
|
|
|
35
35
|
export function parseImage(element, parentId, index) {
|
|
36
36
|
const id = generateId();
|
|
37
37
|
|
|
38
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
39
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
40
|
+
|
|
38
41
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
39
42
|
const spacing = parseSpacing(wrapperStyles);
|
|
40
43
|
const textAlign = parseTextAlign(wrapperStyles['text-align']);
|
|
@@ -63,6 +66,7 @@ export function parseImage(element, parentId, index) {
|
|
|
63
66
|
parentId,
|
|
64
67
|
fractionalIndex: generateFractionalIndex(index),
|
|
65
68
|
attrs: {
|
|
69
|
+
...(elementId ? { id: elementId } : {}),
|
|
66
70
|
alt,
|
|
67
71
|
style: {
|
|
68
72
|
'text-align': textAlign,
|
|
@@ -131,6 +135,9 @@ export function parseImage(element, parentId, index) {
|
|
|
131
135
|
export function parseIcon(element, parentId, index) {
|
|
132
136
|
const id = generateId();
|
|
133
137
|
|
|
138
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
139
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
140
|
+
|
|
134
141
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
135
142
|
const spacing = parseSpacing(wrapperStyles);
|
|
136
143
|
const textAlign = parseTextAlign(wrapperStyles['text-align']);
|
|
@@ -166,6 +173,7 @@ export function parseIcon(element, parentId, index) {
|
|
|
166
173
|
parentId,
|
|
167
174
|
fractionalIndex: generateFractionalIndex(index),
|
|
168
175
|
attrs: {
|
|
176
|
+
...(elementId ? { id: elementId } : {}),
|
|
169
177
|
style: {},
|
|
170
178
|
...animationAttrs,
|
|
171
179
|
},
|
|
@@ -214,6 +222,9 @@ export function parseIcon(element, parentId, index) {
|
|
|
214
222
|
export function parseVideo(element, parentId, index) {
|
|
215
223
|
const id = generateId();
|
|
216
224
|
|
|
225
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
226
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
227
|
+
|
|
217
228
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
218
229
|
const spacing = parseSpacing(wrapperStyles);
|
|
219
230
|
|
|
@@ -237,6 +248,7 @@ export function parseVideo(element, parentId, index) {
|
|
|
237
248
|
parentId,
|
|
238
249
|
fractionalIndex: generateFractionalIndex(index),
|
|
239
250
|
attrs: {
|
|
251
|
+
...(elementId ? { id: elementId } : {}),
|
|
240
252
|
'data-video-type': videoType,
|
|
241
253
|
'data-skip-background-settings': background.color ? 'false' : 'true',
|
|
242
254
|
'data-skip-shadow-settings': shadow ? 'false' : 'true',
|
|
@@ -288,6 +300,9 @@ export function parseVideo(element, parentId, index) {
|
|
|
288
300
|
export function parseDivider(element, parentId, index) {
|
|
289
301
|
const id = generateId();
|
|
290
302
|
|
|
303
|
+
// Get element-id for scroll-to/show-hide targeting
|
|
304
|
+
const elementId = element.getAttribute('id') || element.getAttribute('data-element-id');
|
|
305
|
+
|
|
291
306
|
const wrapperStyles = parseInlineStyle(element.getAttribute('style') || '');
|
|
292
307
|
const spacing = parseSpacing(wrapperStyles);
|
|
293
308
|
|
|
@@ -333,6 +348,7 @@ export function parseDivider(element, parentId, index) {
|
|
|
333
348
|
parentId,
|
|
334
349
|
fractionalIndex: generateFractionalIndex(index),
|
|
335
350
|
attrs: {
|
|
351
|
+
...(elementId ? { id: elementId } : {}),
|
|
336
352
|
style: {},
|
|
337
353
|
},
|
|
338
354
|
params: {
|
package/src/parsers/text.js
CHANGED
|
@@ -73,10 +73,19 @@ function parseTextElement(
|
|
|
73
73
|
? parseFontFamily(fontAttr)
|
|
74
74
|
: parseFontFamily(textStyles["font-family"]);
|
|
75
75
|
|
|
76
|
+
// Get color: element data-color > inline style > page color > default
|
|
76
77
|
const colorAttr = element.getAttribute("data-color");
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
let color;
|
|
79
|
+
if (colorAttr) {
|
|
80
|
+
color = normalizeColor(colorAttr);
|
|
81
|
+
} else if (textStyles.color) {
|
|
82
|
+
color = normalizeColor(textStyles.color);
|
|
83
|
+
} else {
|
|
84
|
+
// Fall back to page-level color from ContentNode
|
|
85
|
+
const contentNode = element.closest('[data-type="ContentNode"]');
|
|
86
|
+
const pageColor = contentNode?.getAttribute("data-color") || contentNode?.getAttribute("data-text-color");
|
|
87
|
+
color = pageColor ? normalizeColor(pageColor) : "#000000";
|
|
88
|
+
}
|
|
80
89
|
|
|
81
90
|
const alignAttr = element.getAttribute("data-align");
|
|
82
91
|
const textAlign = alignAttr || parseTextAlign(textStyles["text-align"]);
|