payload-wordpress-migrator 0.0.22
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/LICENSE +21 -0
- package/README.md +586 -0
- package/dist/components/BeforeDashboardClient.d.ts +14 -0
- package/dist/components/BeforeDashboardClient.js +225 -0
- package/dist/components/BeforeDashboardClient.js.map +1 -0
- package/dist/components/BeforeDashboardClient.module.css +175 -0
- package/dist/components/BeforeDashboardServer.d.ts +1 -0
- package/dist/components/BeforeDashboardServer.js +29 -0
- package/dist/components/BeforeDashboardServer.js.map +1 -0
- package/dist/components/ContentTypeSelect.d.ts +4 -0
- package/dist/components/ContentTypeSelect.js +147 -0
- package/dist/components/ContentTypeSelect.js.map +1 -0
- package/dist/components/FieldMappingConfiguration.d.ts +5 -0
- package/dist/components/FieldMappingConfiguration.js +361 -0
- package/dist/components/FieldMappingConfiguration.js.map +1 -0
- package/dist/components/FieldMappingConfiguration.module.css +75 -0
- package/dist/components/MigrationDashboardClient.d.ts +6 -0
- package/dist/components/MigrationDashboardClient.js +49 -0
- package/dist/components/MigrationDashboardClient.js.map +1 -0
- package/dist/components/MigrationDashboardClient.module.css +749 -0
- package/dist/components/SimpleFieldMapping.d.ts +5 -0
- package/dist/components/SimpleFieldMapping.js +437 -0
- package/dist/components/SimpleFieldMapping.js.map +1 -0
- package/dist/components/dashboard/JobActionButtons.d.ts +8 -0
- package/dist/components/dashboard/JobActionButtons.js +91 -0
- package/dist/components/dashboard/JobActionButtons.js.map +1 -0
- package/dist/components/dashboard/JobsTable.d.ts +6 -0
- package/dist/components/dashboard/JobsTable.js +86 -0
- package/dist/components/dashboard/JobsTable.js.map +1 -0
- package/dist/components/dashboard/LogViewer.d.ts +3 -0
- package/dist/components/dashboard/LogViewer.js +35 -0
- package/dist/components/dashboard/LogViewer.js.map +1 -0
- package/dist/components/dashboard/SiteConfigPanel.d.ts +12 -0
- package/dist/components/dashboard/SiteConfigPanel.js +205 -0
- package/dist/components/dashboard/SiteConfigPanel.js.map +1 -0
- package/dist/components/dashboard/StatsOverview.d.ts +5 -0
- package/dist/components/dashboard/StatsOverview.js +72 -0
- package/dist/components/dashboard/StatsOverview.js.map +1 -0
- package/dist/components/dashboard/index.d.ts +7 -0
- package/dist/components/dashboard/index.js +7 -0
- package/dist/components/dashboard/index.js.map +1 -0
- package/dist/components/dashboard/types.d.ts +46 -0
- package/dist/components/dashboard/types.js +2 -0
- package/dist/components/dashboard/types.js.map +1 -0
- package/dist/components/dashboard/useMigrationDashboard.d.ts +15 -0
- package/dist/components/dashboard/useMigrationDashboard.js +584 -0
- package/dist/components/dashboard/useMigrationDashboard.js.map +1 -0
- package/dist/exports/client.d.ts +4 -0
- package/dist/exports/client.js +5 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/exports/rsc.d.ts +1 -0
- package/dist/exports/rsc.js +2 -0
- package/dist/exports/rsc.js.map +1 -0
- package/dist/index.d.ts +101 -0
- package/dist/index.js +443 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/content/blocks.d.ts +6 -0
- package/dist/utils/content/blocks.js +93 -0
- package/dist/utils/content/blocks.js.map +1 -0
- package/dist/utils/content/fieldMapping.d.ts +9 -0
- package/dist/utils/content/fieldMapping.js +218 -0
- package/dist/utils/content/fieldMapping.js.map +1 -0
- package/dist/utils/content/index.d.ts +4 -0
- package/dist/utils/content/index.js +4 -0
- package/dist/utils/content/index.js.map +1 -0
- package/dist/utils/content/transformer.d.ts +5 -0
- package/dist/utils/content/transformer.js +323 -0
- package/dist/utils/content/transformer.js.map +1 -0
- package/dist/utils/endpoints/handlers.d.ts +9 -0
- package/dist/utils/endpoints/handlers.js +201 -0
- package/dist/utils/endpoints/handlers.js.map +1 -0
- package/dist/utils/endpoints/index.d.ts +2 -0
- package/dist/utils/endpoints/index.js +2 -0
- package/dist/utils/endpoints/index.js.map +1 -0
- package/dist/utils/fields/analyzer.d.ts +7 -0
- package/dist/utils/fields/analyzer.js +502 -0
- package/dist/utils/fields/analyzer.js.map +1 -0
- package/dist/utils/fields/index.d.ts +2 -0
- package/dist/utils/fields/index.js +2 -0
- package/dist/utils/fields/index.js.map +1 -0
- package/dist/utils/helpers/auth.d.ts +9 -0
- package/dist/utils/helpers/auth.js +50 -0
- package/dist/utils/helpers/auth.js.map +1 -0
- package/dist/utils/helpers/cache.d.ts +11 -0
- package/dist/utils/helpers/cache.js +47 -0
- package/dist/utils/helpers/cache.js.map +1 -0
- package/dist/utils/helpers/concurrency.d.ts +2 -0
- package/dist/utils/helpers/concurrency.js +26 -0
- package/dist/utils/helpers/concurrency.js.map +1 -0
- package/dist/utils/helpers/index.d.ts +8 -0
- package/dist/utils/helpers/index.js +8 -0
- package/dist/utils/helpers/index.js.map +1 -0
- package/dist/utils/helpers/objectHelpers.d.ts +3 -0
- package/dist/utils/helpers/objectHelpers.js +22 -0
- package/dist/utils/helpers/objectHelpers.js.map +1 -0
- package/dist/utils/helpers/rateLimiter.d.ts +10 -0
- package/dist/utils/helpers/rateLimiter.js +29 -0
- package/dist/utils/helpers/rateLimiter.js.map +1 -0
- package/dist/utils/helpers/responses.d.ts +3 -0
- package/dist/utils/helpers/responses.js +23 -0
- package/dist/utils/helpers/responses.js.map +1 -0
- package/dist/utils/helpers/wpHelpers.d.ts +6 -0
- package/dist/utils/helpers/wpHelpers.js +29 -0
- package/dist/utils/helpers/wpHelpers.js.map +1 -0
- package/dist/utils/lexical/constants.d.ts +37 -0
- package/dist/utils/lexical/constants.js +58 -0
- package/dist/utils/lexical/constants.js.map +1 -0
- package/dist/utils/lexical/htmlParser.d.ts +20 -0
- package/dist/utils/lexical/htmlParser.js +253 -0
- package/dist/utils/lexical/htmlParser.js.map +1 -0
- package/dist/utils/lexical/htmlToLexicalConverter.d.ts +55 -0
- package/dist/utils/lexical/htmlToLexicalConverter.js +999 -0
- package/dist/utils/lexical/htmlToLexicalConverter.js.map +1 -0
- package/dist/utils/lexical/index.d.ts +5 -0
- package/dist/utils/lexical/index.js +4 -0
- package/dist/utils/lexical/index.js.map +1 -0
- package/dist/utils/lexical/nodeFactories.d.ts +21 -0
- package/dist/utils/lexical/nodeFactories.js +91 -0
- package/dist/utils/lexical/nodeFactories.js.map +1 -0
- package/dist/utils/lexical/preprocessor.d.ts +4 -0
- package/dist/utils/lexical/preprocessor.js +302 -0
- package/dist/utils/lexical/preprocessor.js.map +1 -0
- package/dist/utils/media/download.d.ts +7 -0
- package/dist/utils/media/download.js +85 -0
- package/dist/utils/media/download.js.map +1 -0
- package/dist/utils/media/extraction.d.ts +12 -0
- package/dist/utils/media/extraction.js +58 -0
- package/dist/utils/media/extraction.js.map +1 -0
- package/dist/utils/media/import.d.ts +7 -0
- package/dist/utils/media/import.js +146 -0
- package/dist/utils/media/import.js.map +1 -0
- package/dist/utils/media/index.d.ts +6 -0
- package/dist/utils/media/index.js +6 -0
- package/dist/utils/media/index.js.map +1 -0
- package/dist/utils/media/upload.d.ts +4 -0
- package/dist/utils/media/upload.js +46 -0
- package/dist/utils/media/upload.js.map +1 -0
- package/dist/utils/media/validation.d.ts +8 -0
- package/dist/utils/media/validation.js +60 -0
- package/dist/utils/media/validation.js.map +1 -0
- package/dist/utils/migration/index.d.ts +3 -0
- package/dist/utils/migration/index.js +3 -0
- package/dist/utils/migration/index.js.map +1 -0
- package/dist/utils/migration/jobCrud.d.ts +4 -0
- package/dist/utils/migration/jobCrud.js +380 -0
- package/dist/utils/migration/jobCrud.js.map +1 -0
- package/dist/utils/migration/orchestrator.d.ts +5 -0
- package/dist/utils/migration/orchestrator.js +756 -0
- package/dist/utils/migration/orchestrator.js.map +1 -0
- package/dist/utils/types.d.ts +201 -0
- package/dist/utils/types.js +14 -0
- package/dist/utils/types.js.map +1 -0
- package/dist/utils/wordpress/client.d.ts +61 -0
- package/dist/utils/wordpress/client.js +365 -0
- package/dist/utils/wordpress/client.js.map +1 -0
- package/dist/utils/wordpress/index.d.ts +2 -0
- package/dist/utils/wordpress/index.js +2 -0
- package/dist/utils/wordpress/index.js.map +1 -0
- package/dist/utils/wordpressApi.d.ts +11 -0
- package/dist/utils/wordpressApi.js +25 -0
- package/dist/utils/wordpressApi.js.map +1 -0
- package/package.json +155 -0
|
@@ -0,0 +1,999 @@
|
|
|
1
|
+
import { BLOCK_ELEMENT_MAP, INLINE_FORMAT_MAP, TEXT_FORMAT_BOLD, TEXT_FORMAT_ITALIC, TEXT_FORMAT_UNDERLINE, TEXT_FORMAT_STRIKETHROUGH } from './constants.js';
|
|
2
|
+
import { SimpleHTMLParser } from './htmlParser.js';
|
|
3
|
+
|
|
4
|
+
class EnhancedHtmlToLexicalConverter {
|
|
5
|
+
cleanWhitespaceOnlyParagraphs(children) {
|
|
6
|
+
return children.filter((child)=>{
|
|
7
|
+
if (child.type === 'list') {
|
|
8
|
+
const list = child;
|
|
9
|
+
return list.children && list.children.length > 0;
|
|
10
|
+
}
|
|
11
|
+
if (child.type !== 'paragraph') {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
const paragraph = child;
|
|
15
|
+
if (!paragraph.children || paragraph.children.length === 0) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
if (paragraph.children.length === 1 && paragraph.children[0].type === 'text') {
|
|
19
|
+
const textNode = paragraph.children[0];
|
|
20
|
+
return textNode.text.trim().length > 0;
|
|
21
|
+
}
|
|
22
|
+
return true;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
convertBlockElement(element) {
|
|
26
|
+
const tagName = element.tagName.toLowerCase();
|
|
27
|
+
const lexicalType = BLOCK_ELEMENT_MAP[tagName];
|
|
28
|
+
switch(lexicalType){
|
|
29
|
+
case 'heading':
|
|
30
|
+
return this.convertHeading(element);
|
|
31
|
+
case 'list':
|
|
32
|
+
return this.convertList(element);
|
|
33
|
+
case 'listitem':
|
|
34
|
+
return this.convertListItem(element);
|
|
35
|
+
case 'quote':
|
|
36
|
+
return this.convertQuote(element);
|
|
37
|
+
default:
|
|
38
|
+
return this.convertParagraph(element);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
convertChildren(children, isRoot = false, parentType) {
|
|
42
|
+
const result = [];
|
|
43
|
+
let currentParagraph = null;
|
|
44
|
+
for (const child of children){
|
|
45
|
+
if (typeof child === 'string') {
|
|
46
|
+
const normalizedText = this.normalizeTextWhitespace(child);
|
|
47
|
+
if (normalizedText) {
|
|
48
|
+
if (isRoot) {
|
|
49
|
+
if (!currentParagraph) {
|
|
50
|
+
currentParagraph = this.createParagraph();
|
|
51
|
+
result.push(currentParagraph);
|
|
52
|
+
}
|
|
53
|
+
const textNode = this.createTextNode(normalizedText, this.getCurrentFormat());
|
|
54
|
+
currentParagraph.children.push(textNode);
|
|
55
|
+
} else {
|
|
56
|
+
const textNode = this.createTextNode(normalizedText, this.getCurrentFormat());
|
|
57
|
+
result.push(textNode);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
const convertedNodes = this.convertElement(child, parentType);
|
|
62
|
+
for (const node of convertedNodes){
|
|
63
|
+
if (this.isBlockElement(node)) {
|
|
64
|
+
if (parentType === 'paragraph') {
|
|
65
|
+
console.warn(`Preventing block element ${node.type} inside paragraph, converting to text`);
|
|
66
|
+
if (currentParagraph && node.type === 'text') {
|
|
67
|
+
currentParagraph.children.push(node);
|
|
68
|
+
}
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (node.type === 'block') {
|
|
72
|
+
if (!node.fields || !node.fields.blockType) {
|
|
73
|
+
console.error('Invalid block structure, skipping:', node);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
currentParagraph = null;
|
|
78
|
+
result.push(node);
|
|
79
|
+
} else {
|
|
80
|
+
if (isRoot) {
|
|
81
|
+
if (!currentParagraph) {
|
|
82
|
+
currentParagraph = this.createParagraph();
|
|
83
|
+
result.push(currentParagraph);
|
|
84
|
+
}
|
|
85
|
+
currentParagraph.children.push(node);
|
|
86
|
+
} else {
|
|
87
|
+
result.push(node);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return result.filter((node)=>node !== null);
|
|
94
|
+
}
|
|
95
|
+
convertElement(element, parentType) {
|
|
96
|
+
const tagName = element.tagName.toLowerCase();
|
|
97
|
+
if (tagName === 'div') {
|
|
98
|
+
const className = element.attributes.class || '';
|
|
99
|
+
if (className.includes('wp-block-image')) {
|
|
100
|
+
const images = this.extractImagesFromElement(element);
|
|
101
|
+
if (images.length > 0) {
|
|
102
|
+
const caption = this.extractFigcaption(element);
|
|
103
|
+
const mediaBlock = this.convertImageWithCaption(images[0], caption);
|
|
104
|
+
return [
|
|
105
|
+
mediaBlock
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (className.includes('wp-block-column')) {
|
|
110
|
+
const images = this.extractImagesFromElement(element);
|
|
111
|
+
if (images.length > 0) {
|
|
112
|
+
const hasImageBlock = this.findElementByTagName(element, 'div')?.attributes.class?.includes('wp-block-image');
|
|
113
|
+
if (!hasImageBlock) {
|
|
114
|
+
const caption = this.extractFigcaption(element);
|
|
115
|
+
const mediaBlock = this.convertImageWithCaption(images[0], caption);
|
|
116
|
+
return [
|
|
117
|
+
mediaBlock
|
|
118
|
+
];
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (className.includes('wp-block-embed')) {
|
|
123
|
+
const iframeBlock = this.convertWordPressEmbedBlock(element);
|
|
124
|
+
if (iframeBlock) {
|
|
125
|
+
return [
|
|
126
|
+
iframeBlock
|
|
127
|
+
];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (className.includes('wp-block-wpsp-faq') && !className.includes('wp-block-wpsp-faq-child')) {
|
|
131
|
+
const accordionBlock = this.convertSchemaProFaq(element);
|
|
132
|
+
if (accordionBlock) {
|
|
133
|
+
return [
|
|
134
|
+
accordionBlock
|
|
135
|
+
];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (tagName === 'div' && element.attributes.class?.includes('wp-block-image')) {
|
|
140
|
+
return this.convertWordPressImageBlock(element);
|
|
141
|
+
}
|
|
142
|
+
if (BLOCK_ELEMENT_MAP[tagName]) {
|
|
143
|
+
return [
|
|
144
|
+
this.convertBlockElement(element)
|
|
145
|
+
];
|
|
146
|
+
}
|
|
147
|
+
if (INLINE_FORMAT_MAP[tagName]) {
|
|
148
|
+
return this.convertInlineFormatting(element);
|
|
149
|
+
}
|
|
150
|
+
switch(tagName){
|
|
151
|
+
case 'a':
|
|
152
|
+
return [
|
|
153
|
+
this.convertLink(element)
|
|
154
|
+
];
|
|
155
|
+
case 'br':
|
|
156
|
+
return [
|
|
157
|
+
this.createLineBreak()
|
|
158
|
+
];
|
|
159
|
+
case 'figure':
|
|
160
|
+
return this.convertFigure(element);
|
|
161
|
+
case 'hr':
|
|
162
|
+
return [
|
|
163
|
+
this.createHorizontalRule()
|
|
164
|
+
];
|
|
165
|
+
case 'iframe':
|
|
166
|
+
return [
|
|
167
|
+
this.convertIframe(element)
|
|
168
|
+
];
|
|
169
|
+
case 'img':
|
|
170
|
+
return [
|
|
171
|
+
this.convertImage(element)
|
|
172
|
+
];
|
|
173
|
+
case 'picture':
|
|
174
|
+
return this.convertPicture(element);
|
|
175
|
+
case 'span':
|
|
176
|
+
return this.convertSpan(element, parentType);
|
|
177
|
+
default:
|
|
178
|
+
return this.convertChildren(element.children, false, parentType);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
convertFigure(element) {
|
|
182
|
+
const iframe = this.findElementByTagName(element, 'iframe');
|
|
183
|
+
if (iframe) {
|
|
184
|
+
return [
|
|
185
|
+
this.convertIframe(iframe)
|
|
186
|
+
];
|
|
187
|
+
}
|
|
188
|
+
const images = this.extractImagesFromElement(element);
|
|
189
|
+
if (images.length > 0) {
|
|
190
|
+
const caption = this.extractFigcaption(element);
|
|
191
|
+
const mediaBlock = this.convertImageWithCaption(images[0], caption);
|
|
192
|
+
return [
|
|
193
|
+
mediaBlock
|
|
194
|
+
];
|
|
195
|
+
}
|
|
196
|
+
return this.convertChildren(element.children, false, 'figure');
|
|
197
|
+
}
|
|
198
|
+
convertHeading(element) {
|
|
199
|
+
const children = this.convertChildren(element.children, false, 'heading');
|
|
200
|
+
return {
|
|
201
|
+
type: 'heading',
|
|
202
|
+
children: children.length > 0 ? children : [
|
|
203
|
+
this.createTextNode('', 0)
|
|
204
|
+
],
|
|
205
|
+
direction: 'ltr',
|
|
206
|
+
format: '',
|
|
207
|
+
indent: 0,
|
|
208
|
+
tag: element.tagName,
|
|
209
|
+
version: 1
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
convertIframe(element) {
|
|
213
|
+
const src = element.attributes.src || '';
|
|
214
|
+
const title = element.attributes.title || '';
|
|
215
|
+
const heightAttr = element.attributes.height || '';
|
|
216
|
+
const loadingAttr = element.attributes.loading || 'lazy';
|
|
217
|
+
let height = null;
|
|
218
|
+
if (heightAttr) {
|
|
219
|
+
const parsedHeight = parseInt(heightAttr, 10);
|
|
220
|
+
if (!isNaN(parsedHeight) && parsedHeight > 0) {
|
|
221
|
+
height = parsedHeight;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const normalizedUrl = this.normalizeEmbedUrl(src);
|
|
225
|
+
return {
|
|
226
|
+
type: 'block',
|
|
227
|
+
fields: {
|
|
228
|
+
id: this.generateBlockId(),
|
|
229
|
+
blockName: title || 'Embedded Content',
|
|
230
|
+
blockType: 'iframeBlock',
|
|
231
|
+
height,
|
|
232
|
+
loading: loadingAttr === 'eager' ? 'eager' : 'lazy',
|
|
233
|
+
title: title || null,
|
|
234
|
+
url: normalizedUrl
|
|
235
|
+
},
|
|
236
|
+
version: 2
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
convertImage(element) {
|
|
240
|
+
const src = element.attributes.src || '';
|
|
241
|
+
const alt = element.attributes.alt || '';
|
|
242
|
+
const title = element.attributes.title || '';
|
|
243
|
+
return {
|
|
244
|
+
type: 'block',
|
|
245
|
+
fields: {
|
|
246
|
+
id: this.generateBlockId(),
|
|
247
|
+
blockName: title || alt || 'Migrated Image',
|
|
248
|
+
blockType: 'mediaBlock',
|
|
249
|
+
media: null,
|
|
250
|
+
__migrationMeta: {
|
|
251
|
+
alt,
|
|
252
|
+
needsMediaImport: true,
|
|
253
|
+
originalSrc: src,
|
|
254
|
+
title
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
version: 2
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
convertImageWithCaption(imgElement, caption) {
|
|
261
|
+
const src = imgElement.attributes.src;
|
|
262
|
+
const alt = imgElement.attributes.alt || '';
|
|
263
|
+
const title = imgElement.attributes.title || '';
|
|
264
|
+
if (!src) {
|
|
265
|
+
console.warn('Image element missing src attribute');
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
const blockId = Math.random().toString(36).substring(2, 11);
|
|
269
|
+
const blockName = alt || title || 'Media Block';
|
|
270
|
+
const validCaption = caption || null;
|
|
271
|
+
const mediaBlock = {
|
|
272
|
+
type: 'block',
|
|
273
|
+
fields: {
|
|
274
|
+
id: blockId,
|
|
275
|
+
blockName,
|
|
276
|
+
blockType: 'mediaBlock',
|
|
277
|
+
media: null,
|
|
278
|
+
__migrationMeta: {
|
|
279
|
+
alt,
|
|
280
|
+
caption: validCaption,
|
|
281
|
+
needsMediaImport: true,
|
|
282
|
+
originalSrc: src,
|
|
283
|
+
title
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
version: 2
|
|
287
|
+
};
|
|
288
|
+
if (!mediaBlock.type || !mediaBlock.fields || !mediaBlock.fields.blockType) {
|
|
289
|
+
console.error('Invalid MediaBlock structure created:', mediaBlock);
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
return mediaBlock;
|
|
293
|
+
}
|
|
294
|
+
convertInlineFormatting(element) {
|
|
295
|
+
const formatBit = INLINE_FORMAT_MAP[element.tagName.toLowerCase()];
|
|
296
|
+
this.formatStack.push(formatBit);
|
|
297
|
+
const result = [];
|
|
298
|
+
for (const child of element.children){
|
|
299
|
+
if (typeof child === 'string') {
|
|
300
|
+
if (child.trim()) {
|
|
301
|
+
const textNode = this.createTextNode(child, this.getCurrentFormat());
|
|
302
|
+
result.push(textNode);
|
|
303
|
+
}
|
|
304
|
+
} else {
|
|
305
|
+
const convertedNodes = this.convertElement(child);
|
|
306
|
+
result.push(...convertedNodes);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
this.formatStack.pop();
|
|
310
|
+
return result;
|
|
311
|
+
}
|
|
312
|
+
convertLink(element) {
|
|
313
|
+
const href = element.attributes.href || '';
|
|
314
|
+
element.attributes.title || '';
|
|
315
|
+
const target = element.attributes.target || '';
|
|
316
|
+
element.attributes.rel || '';
|
|
317
|
+
let cleanUrl = href.trim();
|
|
318
|
+
if (!cleanUrl || cleanUrl === '#' || cleanUrl.startsWith('javascript:') || cleanUrl.length < 3) {
|
|
319
|
+
console.warn(`Converting invalid link to text: "${href}"`);
|
|
320
|
+
const children = this.convertChildren(element.children, false, 'text');
|
|
321
|
+
return children.length > 0 ? children[0] : this.createTextNode(href || 'link', 0);
|
|
322
|
+
}
|
|
323
|
+
if (!cleanUrl.startsWith('http://') && !cleanUrl.startsWith('https://') && !cleanUrl.startsWith('/') && !cleanUrl.startsWith('#') && !cleanUrl.startsWith('mailto:') && !cleanUrl.startsWith('tel:')) {
|
|
324
|
+
cleanUrl = 'https://' + cleanUrl;
|
|
325
|
+
}
|
|
326
|
+
try {
|
|
327
|
+
if (cleanUrl.startsWith('http://') || cleanUrl.startsWith('https://')) {
|
|
328
|
+
new URL(cleanUrl);
|
|
329
|
+
}
|
|
330
|
+
} catch (_error) {
|
|
331
|
+
console.warn(`Converting malformed URL to text: "${cleanUrl}"`);
|
|
332
|
+
const children = this.convertChildren(element.children, false, 'text');
|
|
333
|
+
return children.length > 0 ? children[0] : this.createTextNode(cleanUrl, 0);
|
|
334
|
+
}
|
|
335
|
+
const children = this.convertChildren(element.children, false, 'link');
|
|
336
|
+
return {
|
|
337
|
+
type: 'link',
|
|
338
|
+
children: children.length > 0 ? children : [
|
|
339
|
+
this.createTextNode(cleanUrl, 0)
|
|
340
|
+
],
|
|
341
|
+
direction: 'ltr',
|
|
342
|
+
fields: {
|
|
343
|
+
linkType: 'custom',
|
|
344
|
+
newTab: target === '_blank',
|
|
345
|
+
url: cleanUrl
|
|
346
|
+
},
|
|
347
|
+
format: '',
|
|
348
|
+
indent: 0,
|
|
349
|
+
version: 1
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
convertList(element) {
|
|
353
|
+
const listType = element.tagName === 'ol' ? 'number' : 'bullet';
|
|
354
|
+
const children = this.convertChildren(element.children, false, 'list');
|
|
355
|
+
return {
|
|
356
|
+
type: 'list',
|
|
357
|
+
children: children.length > 0 ? children : [],
|
|
358
|
+
direction: 'ltr',
|
|
359
|
+
format: '',
|
|
360
|
+
indent: 0,
|
|
361
|
+
listType,
|
|
362
|
+
start: element.attributes.start ? parseInt(element.attributes.start) : 1,
|
|
363
|
+
tag: element.tagName,
|
|
364
|
+
version: 1
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
convertListItem(element) {
|
|
368
|
+
const children = this.convertChildren(element.children, false, 'listitem');
|
|
369
|
+
return {
|
|
370
|
+
type: 'listitem',
|
|
371
|
+
children: children.length > 0 ? children : [
|
|
372
|
+
this.createTextNode('', 0)
|
|
373
|
+
],
|
|
374
|
+
direction: 'ltr',
|
|
375
|
+
format: '',
|
|
376
|
+
indent: 0,
|
|
377
|
+
value: 1,
|
|
378
|
+
version: 1
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
convertParagraph(element) {
|
|
382
|
+
const children = this.convertChildren(element.children, false, 'paragraph');
|
|
383
|
+
return {
|
|
384
|
+
type: 'paragraph',
|
|
385
|
+
children: children.length > 0 ? children : [
|
|
386
|
+
this.createTextNode('', 0)
|
|
387
|
+
],
|
|
388
|
+
direction: 'ltr',
|
|
389
|
+
format: '',
|
|
390
|
+
indent: 0,
|
|
391
|
+
version: 1
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
convertPicture(element) {
|
|
395
|
+
const images = this.extractImagesFromElement(element);
|
|
396
|
+
if (images.length > 0) {
|
|
397
|
+
const bestSrc = this.getBestPictureSource(element) || images[0].attributes.src;
|
|
398
|
+
const enhancedImage = {
|
|
399
|
+
...images[0],
|
|
400
|
+
attributes: {
|
|
401
|
+
...images[0].attributes,
|
|
402
|
+
src: bestSrc
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
const parentFigure = this.findParentElement(element, 'figure');
|
|
406
|
+
const caption = parentFigure ? this.extractFigcaption(parentFigure) : null;
|
|
407
|
+
return [
|
|
408
|
+
this.convertImageWithCaption(enhancedImage, caption)
|
|
409
|
+
];
|
|
410
|
+
}
|
|
411
|
+
return [];
|
|
412
|
+
}
|
|
413
|
+
convertQuote(element) {
|
|
414
|
+
const children = this.convertChildren(element.children, true, 'quote');
|
|
415
|
+
return {
|
|
416
|
+
type: 'quote',
|
|
417
|
+
children: children.length > 0 ? children : [
|
|
418
|
+
this.createEmptyParagraph()
|
|
419
|
+
],
|
|
420
|
+
direction: 'ltr',
|
|
421
|
+
format: '',
|
|
422
|
+
indent: 0,
|
|
423
|
+
version: 1
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
// Schema Pro FAQ plugin renders FAQ items as nested divs with class-based structure:
|
|
427
|
+
// .wp-block-wpsp-faq-child > .wpsp-question (question text)
|
|
428
|
+
// > .wpsp-faq-content (answer HTML)
|
|
429
|
+
// We map these to PayloadCMS accordion blocks so the content remains structured
|
|
430
|
+
// rather than being flattened into plain paragraphs.
|
|
431
|
+
convertSchemaProFaq(element) {
|
|
432
|
+
const faqItems = this.findAllElementsByClassName(element, 'wp-block-wpsp-faq-child');
|
|
433
|
+
if (faqItems.length === 0) {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
const accordionItems = [];
|
|
437
|
+
for (const faqItem of faqItems){
|
|
438
|
+
const questionSpan = this.findElementByClassName(faqItem, 'wpsp-question');
|
|
439
|
+
const question = questionSpan ? this.extractTextFromElement(questionSpan) : '';
|
|
440
|
+
const answerDiv = this.findElementByClassName(faqItem, 'wpsp-faq-content');
|
|
441
|
+
let answerContent = null;
|
|
442
|
+
if (answerDiv) {
|
|
443
|
+
const answerChildren = this.convertChildren(answerDiv.children, true, 'accordion-content');
|
|
444
|
+
answerContent = {
|
|
445
|
+
root: {
|
|
446
|
+
type: 'root',
|
|
447
|
+
children: answerChildren.length > 0 ? answerChildren : [
|
|
448
|
+
this.createEmptyParagraph()
|
|
449
|
+
],
|
|
450
|
+
direction: 'ltr',
|
|
451
|
+
format: '',
|
|
452
|
+
indent: 0,
|
|
453
|
+
version: 1
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
if (question) {
|
|
458
|
+
accordionItems.push({
|
|
459
|
+
content: answerContent || {
|
|
460
|
+
root: {
|
|
461
|
+
type: 'root',
|
|
462
|
+
children: [
|
|
463
|
+
this.createEmptyParagraph()
|
|
464
|
+
],
|
|
465
|
+
direction: 'ltr',
|
|
466
|
+
format: '',
|
|
467
|
+
indent: 0,
|
|
468
|
+
version: 1
|
|
469
|
+
}
|
|
470
|
+
},
|
|
471
|
+
title: question
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
if (accordionItems.length === 0) {
|
|
476
|
+
return null;
|
|
477
|
+
}
|
|
478
|
+
const accordionBlock = {
|
|
479
|
+
type: 'block',
|
|
480
|
+
fields: {
|
|
481
|
+
id: this.generateBlockId(),
|
|
482
|
+
accordionItems: accordionItems.map((item)=>({
|
|
483
|
+
id: this.generateBlockId(),
|
|
484
|
+
content: item.content,
|
|
485
|
+
title: item.title
|
|
486
|
+
})),
|
|
487
|
+
allowMultiple: false,
|
|
488
|
+
blockName: 'FAQ Accordion',
|
|
489
|
+
blockType: 'accordion',
|
|
490
|
+
bottomPadding: 'medium',
|
|
491
|
+
defaultOpen: 'none',
|
|
492
|
+
description: null,
|
|
493
|
+
displayMode: 'simple',
|
|
494
|
+
heading: null,
|
|
495
|
+
theme: 'light',
|
|
496
|
+
topPadding: 'medium'
|
|
497
|
+
},
|
|
498
|
+
version: 2
|
|
499
|
+
};
|
|
500
|
+
return accordionBlock;
|
|
501
|
+
}
|
|
502
|
+
convertSpan(element, parentType) {
|
|
503
|
+
const style = element.attributes.style || '';
|
|
504
|
+
let additionalFormat = 0;
|
|
505
|
+
if (style.includes('font-weight: bold') || style.includes('font-weight:bold')) {
|
|
506
|
+
additionalFormat |= TEXT_FORMAT_BOLD;
|
|
507
|
+
}
|
|
508
|
+
if (style.includes('font-style: italic') || style.includes('font-style:italic')) {
|
|
509
|
+
additionalFormat |= TEXT_FORMAT_ITALIC;
|
|
510
|
+
}
|
|
511
|
+
if (style.includes('text-decoration: underline') || style.includes('text-decoration:underline')) {
|
|
512
|
+
additionalFormat |= TEXT_FORMAT_UNDERLINE;
|
|
513
|
+
}
|
|
514
|
+
if (style.includes('text-decoration: line-through') || style.includes('text-decoration:line-through')) {
|
|
515
|
+
additionalFormat |= TEXT_FORMAT_STRIKETHROUGH;
|
|
516
|
+
}
|
|
517
|
+
if (additionalFormat > 0) {
|
|
518
|
+
this.formatStack.push(additionalFormat);
|
|
519
|
+
const children = this.convertChildren(element.children, false, parentType);
|
|
520
|
+
this.formatStack.pop();
|
|
521
|
+
return children;
|
|
522
|
+
}
|
|
523
|
+
return this.convertChildren(element.children, false, parentType);
|
|
524
|
+
}
|
|
525
|
+
convertWordPressEmbedBlock(element) {
|
|
526
|
+
const iframe = this.findElementByTagName(element, 'iframe');
|
|
527
|
+
if (iframe) {
|
|
528
|
+
return this.convertIframe(iframe);
|
|
529
|
+
}
|
|
530
|
+
const embedWrapper = this.findElementByTagName(element, 'div');
|
|
531
|
+
if (embedWrapper?.attributes.class?.includes('wp-block-embed__wrapper')) {
|
|
532
|
+
const wrapperIframe = this.findElementByTagName(embedWrapper, 'iframe');
|
|
533
|
+
if (wrapperIframe) {
|
|
534
|
+
return this.convertIframe(wrapperIframe);
|
|
535
|
+
}
|
|
536
|
+
const video = this.findElementByTagName(embedWrapper, 'video');
|
|
537
|
+
if (video?.attributes.src) {
|
|
538
|
+
return {
|
|
539
|
+
type: 'block',
|
|
540
|
+
fields: {
|
|
541
|
+
id: this.generateBlockId(),
|
|
542
|
+
blockName: 'Video Embed',
|
|
543
|
+
blockType: 'iframeBlock',
|
|
544
|
+
height: null,
|
|
545
|
+
loading: 'lazy',
|
|
546
|
+
title: null,
|
|
547
|
+
url: video.attributes.src
|
|
548
|
+
},
|
|
549
|
+
version: 2
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
const blockquote = this.findElementByTagName(element, 'blockquote');
|
|
554
|
+
if (blockquote) {
|
|
555
|
+
const link = this.findElementByTagName(blockquote, 'a');
|
|
556
|
+
if (link?.attributes.href) {
|
|
557
|
+
const href = link.attributes.href;
|
|
558
|
+
if (href.includes('twitter.com') || href.includes('x.com')) {
|
|
559
|
+
return {
|
|
560
|
+
type: 'block',
|
|
561
|
+
fields: {
|
|
562
|
+
id: this.generateBlockId(),
|
|
563
|
+
blockName: 'Twitter Embed',
|
|
564
|
+
blockType: 'iframeBlock',
|
|
565
|
+
height: 400,
|
|
566
|
+
loading: 'lazy',
|
|
567
|
+
title: 'Twitter Post',
|
|
568
|
+
url: href
|
|
569
|
+
},
|
|
570
|
+
version: 2
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
return null;
|
|
576
|
+
}
|
|
577
|
+
convertWordPressImageBlock(element) {
|
|
578
|
+
const images = this.extractImagesFromElement(element);
|
|
579
|
+
if (images.length > 0) {
|
|
580
|
+
const caption = this.extractFigcaption(element);
|
|
581
|
+
const mediaBlock = this.convertImageWithCaption(images[0], caption);
|
|
582
|
+
return [
|
|
583
|
+
mediaBlock
|
|
584
|
+
];
|
|
585
|
+
}
|
|
586
|
+
return [
|
|
587
|
+
this.convertBlockElement(element)
|
|
588
|
+
];
|
|
589
|
+
}
|
|
590
|
+
extractTextFromElement(element) {
|
|
591
|
+
let text = '';
|
|
592
|
+
for (const child of element.children){
|
|
593
|
+
if (typeof child === 'string') {
|
|
594
|
+
text += child;
|
|
595
|
+
} else {
|
|
596
|
+
text += this.extractTextFromElement(child);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
return text.trim();
|
|
600
|
+
}
|
|
601
|
+
createEmptyParagraph() {
|
|
602
|
+
return {
|
|
603
|
+
type: 'paragraph',
|
|
604
|
+
children: [
|
|
605
|
+
this.createTextNode('', 0)
|
|
606
|
+
],
|
|
607
|
+
direction: 'ltr',
|
|
608
|
+
format: '',
|
|
609
|
+
indent: 0,
|
|
610
|
+
version: 1
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
findAllElementsByClassName(element, className) {
|
|
614
|
+
const results = [];
|
|
615
|
+
const search = (el)=>{
|
|
616
|
+
if (el.attributes.class?.includes(className)) {
|
|
617
|
+
results.push(el);
|
|
618
|
+
}
|
|
619
|
+
for (const child of el.children){
|
|
620
|
+
if (typeof child !== 'string') {
|
|
621
|
+
search(child);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
search(element);
|
|
626
|
+
return results;
|
|
627
|
+
}
|
|
628
|
+
findElementByClassName(element, className) {
|
|
629
|
+
if (element.attributes.class?.includes(className)) {
|
|
630
|
+
return element;
|
|
631
|
+
}
|
|
632
|
+
for (const child of element.children){
|
|
633
|
+
if (typeof child !== 'string') {
|
|
634
|
+
const found = this.findElementByClassName(child, className);
|
|
635
|
+
if (found) {
|
|
636
|
+
return found;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
createEmptyRoot() {
|
|
643
|
+
return {
|
|
644
|
+
root: {
|
|
645
|
+
type: 'root',
|
|
646
|
+
children: [
|
|
647
|
+
this.createEmptyParagraph()
|
|
648
|
+
],
|
|
649
|
+
direction: 'ltr',
|
|
650
|
+
format: '',
|
|
651
|
+
indent: 0,
|
|
652
|
+
version: 1
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
createHorizontalRule() {
|
|
657
|
+
return {
|
|
658
|
+
type: 'horizontalrule',
|
|
659
|
+
version: 1
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
createLineBreak() {
|
|
663
|
+
return {
|
|
664
|
+
type: 'linebreak',
|
|
665
|
+
version: 1
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
createParagraph() {
|
|
669
|
+
return {
|
|
670
|
+
type: 'paragraph',
|
|
671
|
+
children: [],
|
|
672
|
+
direction: 'ltr',
|
|
673
|
+
format: '',
|
|
674
|
+
indent: 0,
|
|
675
|
+
version: 1
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
createTextNode(text, format) {
|
|
679
|
+
return {
|
|
680
|
+
type: 'text',
|
|
681
|
+
detail: 0,
|
|
682
|
+
format,
|
|
683
|
+
mode: 'normal',
|
|
684
|
+
style: '',
|
|
685
|
+
text,
|
|
686
|
+
version: 1
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
extractFigcaption(element) {
|
|
690
|
+
const figcaption = this.findElementByTagName(element, 'figcaption');
|
|
691
|
+
if (figcaption) {
|
|
692
|
+
const captionChildren = this.convertChildren(figcaption.children, false, 'figcaption');
|
|
693
|
+
if (captionChildren.length > 0) {
|
|
694
|
+
const captionData = {
|
|
695
|
+
root: {
|
|
696
|
+
type: 'root',
|
|
697
|
+
children: captionChildren.length > 0 ? captionChildren : [
|
|
698
|
+
this.createEmptyParagraph()
|
|
699
|
+
],
|
|
700
|
+
direction: 'ltr',
|
|
701
|
+
format: '',
|
|
702
|
+
indent: 0,
|
|
703
|
+
version: 1
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
return captionData;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
return null;
|
|
710
|
+
}
|
|
711
|
+
extractFilename(url) {
|
|
712
|
+
try {
|
|
713
|
+
const urlParts = new URL(url);
|
|
714
|
+
const pathParts = urlParts.pathname.split('/');
|
|
715
|
+
return pathParts[pathParts.length - 1] || 'image';
|
|
716
|
+
} catch {
|
|
717
|
+
return 'image';
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
extractImagesFromElement(element) {
|
|
721
|
+
const images = [];
|
|
722
|
+
if (element.tagName.toLowerCase() === 'img') {
|
|
723
|
+
images.push(element);
|
|
724
|
+
}
|
|
725
|
+
if (element.children) {
|
|
726
|
+
for (const child of element.children){
|
|
727
|
+
if (typeof child === 'object' && child.tagName) {
|
|
728
|
+
const childImages = this.extractImagesFromElement(child);
|
|
729
|
+
images.push(...childImages);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
return images;
|
|
734
|
+
}
|
|
735
|
+
extractTextFromChildren(children) {
|
|
736
|
+
let text = '';
|
|
737
|
+
for (const child of children){
|
|
738
|
+
if (child.type === 'text') {
|
|
739
|
+
text += child.text + ' ';
|
|
740
|
+
} else if (child.children && Array.isArray(child.children)) {
|
|
741
|
+
text += this.extractTextFromChildren(child.children) + ' ';
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
return text.trim();
|
|
745
|
+
}
|
|
746
|
+
extractTextFromNode(node) {
|
|
747
|
+
if (node.type === 'text') {
|
|
748
|
+
return node.text || '';
|
|
749
|
+
}
|
|
750
|
+
if (node.children && Array.isArray(node.children)) {
|
|
751
|
+
return node.children.map((child)=>this.extractTextFromNode(child)).join('');
|
|
752
|
+
}
|
|
753
|
+
return '';
|
|
754
|
+
}
|
|
755
|
+
fallbackConversion(htmlContent) {
|
|
756
|
+
const text = htmlContent.replace(/<[^>]*>/g, '').trim() || '';
|
|
757
|
+
return {
|
|
758
|
+
root: {
|
|
759
|
+
type: 'root',
|
|
760
|
+
children: [
|
|
761
|
+
{
|
|
762
|
+
type: 'paragraph',
|
|
763
|
+
children: [
|
|
764
|
+
{
|
|
765
|
+
type: 'text',
|
|
766
|
+
detail: 0,
|
|
767
|
+
format: 0,
|
|
768
|
+
mode: 'normal',
|
|
769
|
+
style: '',
|
|
770
|
+
text,
|
|
771
|
+
version: 1
|
|
772
|
+
}
|
|
773
|
+
],
|
|
774
|
+
direction: 'ltr',
|
|
775
|
+
format: '',
|
|
776
|
+
indent: 0,
|
|
777
|
+
version: 1
|
|
778
|
+
}
|
|
779
|
+
],
|
|
780
|
+
direction: 'ltr',
|
|
781
|
+
format: '',
|
|
782
|
+
indent: 0,
|
|
783
|
+
version: 1
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
findElementByTagName(element, tagName) {
|
|
788
|
+
if (element.tagName.toLowerCase() === tagName.toLowerCase()) {
|
|
789
|
+
return element;
|
|
790
|
+
}
|
|
791
|
+
if (element.children) {
|
|
792
|
+
for (const child of element.children){
|
|
793
|
+
if (typeof child === 'object' && child.tagName) {
|
|
794
|
+
const found = this.findElementByTagName(child, tagName);
|
|
795
|
+
if (found) {
|
|
796
|
+
return found;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
return null;
|
|
802
|
+
}
|
|
803
|
+
findElementsByTagName(element, tagName) {
|
|
804
|
+
const results = [];
|
|
805
|
+
if (element.tagName.toLowerCase() === tagName.toLowerCase()) {
|
|
806
|
+
results.push(element);
|
|
807
|
+
}
|
|
808
|
+
if (element.children) {
|
|
809
|
+
for (const child of element.children){
|
|
810
|
+
if (typeof child === 'object' && child.tagName) {
|
|
811
|
+
results.push(...this.findElementsByTagName(child, tagName));
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
return results;
|
|
816
|
+
}
|
|
817
|
+
findParentElement(element, tagName) {
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
820
|
+
generateBlockId() {
|
|
821
|
+
return Math.random().toString(36).substr(2, 9);
|
|
822
|
+
}
|
|
823
|
+
getBestPictureSource(element) {
|
|
824
|
+
const sources = this.findElementsByTagName(element, 'source');
|
|
825
|
+
for (const source of sources){
|
|
826
|
+
if (source.attributes.type === 'image/webp' && source.attributes.srcset) {
|
|
827
|
+
const srcset = source.attributes.srcset;
|
|
828
|
+
const firstUrl = srcset.split(',')[0].trim().split(' ')[0];
|
|
829
|
+
return firstUrl;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
for (const source of sources){
|
|
833
|
+
if (source.attributes.srcset) {
|
|
834
|
+
const srcset = source.attributes.srcset;
|
|
835
|
+
const firstUrl = srcset.split(',')[0].trim().split(' ')[0];
|
|
836
|
+
return firstUrl;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
return null;
|
|
840
|
+
}
|
|
841
|
+
normalizeTextWhitespace(text) {
|
|
842
|
+
if (!text) {
|
|
843
|
+
return '';
|
|
844
|
+
}
|
|
845
|
+
const hasLeadingSpace = /^\s/.test(text);
|
|
846
|
+
const hasTrailingSpace = /\s$/.test(text);
|
|
847
|
+
const normalized = text.replace(/\s+/g, ' ').trim();
|
|
848
|
+
if (!normalized && (hasLeadingSpace || hasTrailingSpace)) {
|
|
849
|
+
return ' ';
|
|
850
|
+
}
|
|
851
|
+
if (!normalized) {
|
|
852
|
+
return '';
|
|
853
|
+
}
|
|
854
|
+
let result = normalized;
|
|
855
|
+
if (hasLeadingSpace) {
|
|
856
|
+
result = ' ' + result;
|
|
857
|
+
}
|
|
858
|
+
if (hasTrailingSpace) {
|
|
859
|
+
result = result + ' ';
|
|
860
|
+
}
|
|
861
|
+
return result;
|
|
862
|
+
}
|
|
863
|
+
getCurrentFormat() {
|
|
864
|
+
return this.formatStack.reduce((format, bit)=>format | bit, 0);
|
|
865
|
+
}
|
|
866
|
+
getMimeTypeFromUrl(url) {
|
|
867
|
+
const extension = url.split('.').pop()?.toLowerCase();
|
|
868
|
+
const mimeTypes = {
|
|
869
|
+
gif: 'image/gif',
|
|
870
|
+
jpeg: 'image/jpeg',
|
|
871
|
+
jpg: 'image/jpeg',
|
|
872
|
+
png: 'image/png',
|
|
873
|
+
svg: 'image/svg+xml',
|
|
874
|
+
webp: 'image/webp'
|
|
875
|
+
};
|
|
876
|
+
return mimeTypes[extension || ''] || 'image/jpeg';
|
|
877
|
+
}
|
|
878
|
+
isBlockElement(node) {
|
|
879
|
+
if (!node || typeof node !== 'object') {
|
|
880
|
+
return false;
|
|
881
|
+
}
|
|
882
|
+
const blockTypes = [
|
|
883
|
+
'paragraph',
|
|
884
|
+
'heading',
|
|
885
|
+
'quote',
|
|
886
|
+
'list',
|
|
887
|
+
'listitem',
|
|
888
|
+
'horizontalrule',
|
|
889
|
+
'block'
|
|
890
|
+
];
|
|
891
|
+
return blockTypes.includes(node.type);
|
|
892
|
+
}
|
|
893
|
+
isValidLexicalNode(node) {
|
|
894
|
+
if (!node || typeof node !== 'object') {
|
|
895
|
+
return false;
|
|
896
|
+
}
|
|
897
|
+
if (!node.type || typeof node.type !== 'string') {
|
|
898
|
+
return false;
|
|
899
|
+
}
|
|
900
|
+
if (node.type === 'text') {
|
|
901
|
+
return typeof node.text === 'string' && typeof node.format === 'number' && typeof node.version === 'number';
|
|
902
|
+
}
|
|
903
|
+
if ([
|
|
904
|
+
'heading',
|
|
905
|
+
'link',
|
|
906
|
+
'list',
|
|
907
|
+
'listitem',
|
|
908
|
+
'paragraph',
|
|
909
|
+
'quote'
|
|
910
|
+
].includes(node.type)) {
|
|
911
|
+
return Array.isArray(node.children) && typeof node.version === 'number';
|
|
912
|
+
}
|
|
913
|
+
return typeof node.version === 'number';
|
|
914
|
+
}
|
|
915
|
+
normalizeEmbedUrl(url) {
|
|
916
|
+
if (!url) {
|
|
917
|
+
return url;
|
|
918
|
+
}
|
|
919
|
+
try {
|
|
920
|
+
const urlObj = new URL(url);
|
|
921
|
+
if (urlObj.hostname === 'www.youtube.com' || urlObj.hostname === 'youtube.com') {
|
|
922
|
+
const videoId = urlObj.searchParams.get('v');
|
|
923
|
+
if (videoId) {
|
|
924
|
+
return `https://www.youtube.com/embed/${videoId}`;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
if (urlObj.hostname === 'youtu.be') {
|
|
928
|
+
const videoId = urlObj.pathname.slice(1);
|
|
929
|
+
if (videoId) {
|
|
930
|
+
return `https://www.youtube.com/embed/${videoId}`;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
if (urlObj.hostname === 'vimeo.com' || urlObj.hostname === 'www.vimeo.com') {
|
|
934
|
+
const videoId = urlObj.pathname.split('/').pop();
|
|
935
|
+
if (videoId && /^\d+$/.test(videoId)) {
|
|
936
|
+
return `https://player.vimeo.com/video/${videoId}`;
|
|
937
|
+
}
|
|
938
|
+
}
|
|
939
|
+
} catch {
|
|
940
|
+
// Invalid URL, return as-is
|
|
941
|
+
}
|
|
942
|
+
return url;
|
|
943
|
+
}
|
|
944
|
+
sanitizeHtmlContent(htmlContent) {
|
|
945
|
+
try {
|
|
946
|
+
return htmlContent.replace(/<script[^>]*>.*?<\/script>/gis, '').replace(/<style[^>]*>.*?<\/style>/gis, '').replace(/<!--[\s\S]*?-->/g, '').replace(/<(h[1-6])([^>]*)>\s*<(strong|b)>([^<]*)<\/\3>\s*<\/\1>/gi, '<$1$2>$4</$1>').replace(/<(h[1-6])([^>]*)>\s*<(strong|b)[^>]*>([^<]*)<\/\3>\s*<\/\1>/gi, '<$1$2>$4</$1>').replace(/<br(?:\s[^>]*)?\/?>/gi, '<br />').replace(/<hr(?:\s[^>]*)?\/?>/gi, '<hr />').replace(/<img([^>]*?)(?:\s?\/)?>(?!\s*<\/img>)/gi, '<img$1 />').replace(/\s+(?:id|style)=""\s*/g, ' ').replace(/\s+/g, ' ').trim();
|
|
947
|
+
} catch (error) {
|
|
948
|
+
console.warn('HTML sanitization failed, using original content:', error);
|
|
949
|
+
return htmlContent;
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
convertHtmlToLexical(htmlContent) {
|
|
953
|
+
try {
|
|
954
|
+
if (!htmlContent || htmlContent.trim() === '') {
|
|
955
|
+
return this.createEmptyRoot();
|
|
956
|
+
}
|
|
957
|
+
const sanitizedContent = this.sanitizeHtmlContent(htmlContent);
|
|
958
|
+
const parser = new SimpleHTMLParser(sanitizedContent);
|
|
959
|
+
const parsedHtml = parser.parse();
|
|
960
|
+
const children = this.convertChildren(parsedHtml.children, true);
|
|
961
|
+
const validChildren = children.filter((child)=>{
|
|
962
|
+
if (!child) {
|
|
963
|
+
console.warn('Filtering out null/undefined child');
|
|
964
|
+
return false;
|
|
965
|
+
}
|
|
966
|
+
if (child.type === 'block' && (!child.fields || !child.fields.blockType)) {
|
|
967
|
+
console.warn('Filtering out invalid block with missing fields');
|
|
968
|
+
return false;
|
|
969
|
+
}
|
|
970
|
+
return true;
|
|
971
|
+
});
|
|
972
|
+
const result = {
|
|
973
|
+
root: {
|
|
974
|
+
type: 'root',
|
|
975
|
+
children: validChildren,
|
|
976
|
+
direction: 'ltr',
|
|
977
|
+
format: '',
|
|
978
|
+
indent: 0,
|
|
979
|
+
version: 1
|
|
980
|
+
}
|
|
981
|
+
};
|
|
982
|
+
return result;
|
|
983
|
+
} catch (error) {
|
|
984
|
+
console.warn('HTML to Lexical conversion failed, falling back to simple conversion:', error);
|
|
985
|
+
console.warn('Problematic content preview:', htmlContent?.substring(0, 200) || 'N/A');
|
|
986
|
+
return this.fallbackConversion(htmlContent);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
constructor(){
|
|
990
|
+
this.formatStack = [];
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
const enhancedHtmlToLexicalConverter = new EnhancedHtmlToLexicalConverter();
|
|
994
|
+
const convertHtmlToLexical = (htmlContent)=>{
|
|
995
|
+
return enhancedHtmlToLexicalConverter.convertHtmlToLexical(htmlContent);
|
|
996
|
+
};
|
|
997
|
+
|
|
998
|
+
export { EnhancedHtmlToLexicalConverter, convertHtmlToLexical, enhancedHtmlToLexicalConverter };
|
|
999
|
+
//# sourceMappingURL=htmlToLexicalConverter.js.map
|