@myissue/vue-website-page-builder 3.3.12 → 3.3.14
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 -26
- package/dist/vue-website-page-builder.css +1 -1
- package/dist/vue-website-page-builder.js +5105 -5071
- package/dist/vue-website-page-builder.umd.cjs +37 -37
- package/package.json +1 -1
- package/src/Components/Loaders/GlobalLoader.vue +1 -1
- package/src/Components/Modals/ModalBuilder.vue +2 -2
- package/src/Components/PageBuilder/ToolbarOption/ToolbarOption.vue +2 -2
- package/src/DemoComponents/HomeSection.vue +6 -3
- package/src/DemoComponents/html.json +46 -48
- package/src/PageBuilder/PageBuilder.vue +85 -39
- package/src/composables/PageBuilderService.ts +296 -273
- package/src/stores/page-builder-state.ts +1 -1
- package/src/tailwind-safelist.html +1 -1
- package/src/types/index.ts +2 -4
|
@@ -39,9 +39,9 @@ export class PageBuilderService {
|
|
|
39
39
|
private delay: (ms?: number) => Promise<void>
|
|
40
40
|
private hasStartedEditing: boolean = false
|
|
41
41
|
// Hold data from Database or Backend for updated post
|
|
42
|
-
private originalComponents:
|
|
42
|
+
private originalComponents: BuilderResourceData | undefined = undefined
|
|
43
43
|
// Holds data to be mounted when #pagebuilder is not yet present in the DOM
|
|
44
|
-
private pendingMountData:
|
|
44
|
+
private pendingMountData: BuilderResourceData | null = null
|
|
45
45
|
|
|
46
46
|
constructor(pageBuilderStateStore: ReturnType<typeof usePageBuilderStateStore>) {
|
|
47
47
|
this.hasStartedEditing = false
|
|
@@ -175,36 +175,80 @@ export class PageBuilderService {
|
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
#validateUserProvidedComponents(components:
|
|
179
|
-
|
|
180
|
-
|
|
178
|
+
#validateUserProvidedComponents(components: unknown) {
|
|
179
|
+
const formType =
|
|
180
|
+
this.pageBuilderStateStore.getPageBuilderConfig &&
|
|
181
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
|
|
182
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType
|
|
183
|
+
|
|
184
|
+
if (Array.isArray(components) && components.length === 0) {
|
|
185
|
+
return { error: false as const, message: 'No components provided (empty array).' }
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (
|
|
189
|
+
Array.isArray(components) &&
|
|
190
|
+
components.length >= 1 &&
|
|
191
|
+
formType === 'create' &&
|
|
192
|
+
components
|
|
193
|
+
) {
|
|
181
194
|
return {
|
|
182
|
-
error: true,
|
|
183
|
-
|
|
195
|
+
error: true as const,
|
|
196
|
+
warning:
|
|
197
|
+
'You cannot set formType to create in your configuration while also passing a components data array to the Page Builder. Please set formType to update.',
|
|
198
|
+
status: 'validation_failed',
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (formType === 'create' && components) {
|
|
202
|
+
return {
|
|
203
|
+
error: true as const,
|
|
204
|
+
warning:
|
|
205
|
+
'You cannot set formType to create in your configuration while also passing a components data array to the Page Builder. Please set formType to update.',
|
|
206
|
+
status: 'validation_failed',
|
|
184
207
|
}
|
|
185
208
|
}
|
|
186
209
|
|
|
187
|
-
//
|
|
188
|
-
if (components
|
|
189
|
-
return {
|
|
210
|
+
// Must be an array
|
|
211
|
+
if (!Array.isArray(components)) {
|
|
212
|
+
return {
|
|
213
|
+
error: true as const,
|
|
214
|
+
reason: 'Components data must be an array.',
|
|
215
|
+
}
|
|
190
216
|
}
|
|
191
217
|
|
|
192
218
|
// Check that the first item looks like a component
|
|
193
219
|
const first = components[0]
|
|
194
220
|
|
|
195
|
-
|
|
196
|
-
|
|
221
|
+
// Check that the first item is not an empty object
|
|
222
|
+
if (isEmptyObject(first)) {
|
|
223
|
+
console.error(
|
|
224
|
+
'The first object in the array is empty. Each component must be a non-empty object and include an html_code key.',
|
|
225
|
+
)
|
|
226
|
+
return {
|
|
227
|
+
error: true as const,
|
|
228
|
+
reason:
|
|
229
|
+
"The first object in the array is empty. Each component must be a non-empty object and include an 'html_code' key.",
|
|
230
|
+
}
|
|
231
|
+
}
|
|
197
232
|
|
|
198
|
-
if (
|
|
233
|
+
if (first && 'html_code' in first && typeof first.html_code !== 'string') {
|
|
234
|
+
console.error("The 'html_code' property in the first object must be a string.")
|
|
199
235
|
return {
|
|
200
|
-
error: true,
|
|
201
|
-
reason: "
|
|
236
|
+
error: true as const,
|
|
237
|
+
reason: "The 'html_code' property in the first object must be a string.",
|
|
202
238
|
}
|
|
203
239
|
}
|
|
204
240
|
|
|
205
|
-
|
|
206
|
-
|
|
241
|
+
// Check that the first item has an 'html_code' key
|
|
242
|
+
if (!first || !('html_code' in first)) {
|
|
243
|
+
console.error("The first object in the array must include an 'html_code' key.")
|
|
244
|
+
return {
|
|
245
|
+
error: true as const,
|
|
246
|
+
reason: "The first object in the array must include an 'html_code' key.",
|
|
247
|
+
}
|
|
207
248
|
}
|
|
249
|
+
|
|
250
|
+
// No errors found
|
|
251
|
+
return { error: false as const }
|
|
208
252
|
}
|
|
209
253
|
|
|
210
254
|
#validateConfig(config: PageBuilderConfig): void {
|
|
@@ -225,6 +269,101 @@ export class PageBuilderService {
|
|
|
225
269
|
}
|
|
226
270
|
}
|
|
227
271
|
|
|
272
|
+
#handlePageBuilderNotPresent(passedDataComponents: BuilderResourceData) {
|
|
273
|
+
this.pendingMountData = passedDataComponents
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async #mountPassedComponentsToDOM(components?: BuilderResourceData): Promise<void> {
|
|
277
|
+
const config = this.pageBuilderStateStore.getPageBuilderConfig
|
|
278
|
+
const formType = config && config.updateOrCreate && config.updateOrCreate.formType
|
|
279
|
+
const localStorageData = this.loadStoredComponentsFromStorage()
|
|
280
|
+
|
|
281
|
+
let dataToPass: string
|
|
282
|
+
if (typeof components === 'string') {
|
|
283
|
+
dataToPass = components
|
|
284
|
+
} else if (components !== undefined) {
|
|
285
|
+
dataToPass = JSON.stringify(components)
|
|
286
|
+
} else {
|
|
287
|
+
dataToPass = ''
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
await this.#updateComponentsFromString(dataToPass)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
async tryMountPendingComponents() {
|
|
294
|
+
// Always clear DOM and store before mounting new resource
|
|
295
|
+
this.deleteAllComponentsFromDOM()
|
|
296
|
+
|
|
297
|
+
const localStorageData = this.loadStoredComponentsFromStorage()
|
|
298
|
+
|
|
299
|
+
this.pageBuilderStateStore.setIsLoadingGlobal(true)
|
|
300
|
+
await delay(200)
|
|
301
|
+
const config = this.pageBuilderStateStore.getPageBuilderConfig
|
|
302
|
+
const formType = config && config.updateOrCreate && config.updateOrCreate.formType
|
|
303
|
+
|
|
304
|
+
//
|
|
305
|
+
if (!config) return
|
|
306
|
+
//
|
|
307
|
+
if (
|
|
308
|
+
config &&
|
|
309
|
+
formType === 'update' &&
|
|
310
|
+
localStorageData &&
|
|
311
|
+
typeof localStorageData === 'string' &&
|
|
312
|
+
this.pendingMountData
|
|
313
|
+
) {
|
|
314
|
+
this.pageBuilderStateStore.setHasLocalDraftForUpdate(true)
|
|
315
|
+
}
|
|
316
|
+
//
|
|
317
|
+
//
|
|
318
|
+
//
|
|
319
|
+
//
|
|
320
|
+
if (config && formType === 'update') {
|
|
321
|
+
if (this.pendingMountData) {
|
|
322
|
+
this.#completeBuilderInitialization(this.pendingMountData)
|
|
323
|
+
return
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Pending data for mount is null at this stage
|
|
327
|
+
if (typeof localStorageData === 'string') {
|
|
328
|
+
await this.#updateComponentsFromString(localStorageData)
|
|
329
|
+
this.#completeBuilderInitialization()
|
|
330
|
+
return
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
//
|
|
334
|
+
//
|
|
335
|
+
//
|
|
336
|
+
//
|
|
337
|
+
// Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
|
|
338
|
+
await nextTick()
|
|
339
|
+
// Attach event listeners to all editable elements in the Builder
|
|
340
|
+
await this.#addListenersToEditableElements()
|
|
341
|
+
|
|
342
|
+
this.pageBuilderStateStore.setIsRestoring(false)
|
|
343
|
+
this.pageBuilderStateStore.setIsLoadingGlobal(false)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (config && formType === 'create') {
|
|
347
|
+
// Pending data for mount is null at this stage
|
|
348
|
+
if (typeof localStorageData === 'string') {
|
|
349
|
+
await this.#updateComponentsFromString(localStorageData)
|
|
350
|
+
this.#completeBuilderInitialization()
|
|
351
|
+
return
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
//
|
|
355
|
+
//
|
|
356
|
+
//
|
|
357
|
+
//
|
|
358
|
+
// Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
|
|
359
|
+
await nextTick()
|
|
360
|
+
// Attach event listeners to all editable elements in the Builder
|
|
361
|
+
await this.#addListenersToEditableElements()
|
|
362
|
+
|
|
363
|
+
this.pageBuilderStateStore.setIsRestoring(false)
|
|
364
|
+
this.pageBuilderStateStore.setIsLoadingGlobal(false)
|
|
365
|
+
}
|
|
366
|
+
}
|
|
228
367
|
/**
|
|
229
368
|
* - Entry point for initializing the Page Builder.
|
|
230
369
|
* - Sets the builder as started in the state store.
|
|
@@ -237,62 +376,101 @@ export class PageBuilderService {
|
|
|
237
376
|
*/
|
|
238
377
|
async startBuilder(
|
|
239
378
|
config: PageBuilderConfig,
|
|
240
|
-
|
|
379
|
+
passedComponentsArray?: BuilderResourceData,
|
|
241
380
|
): Promise<StartBuilderResult> {
|
|
242
|
-
console.log('start builder ran..', components)
|
|
243
|
-
if (components) {
|
|
244
|
-
this.#validateUserProvidedComponents(components)
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
return {
|
|
248
|
-
message: 'Page builder started successfully with valid components.',
|
|
249
|
-
}
|
|
250
|
-
|
|
251
381
|
// Reactive flag signals to the UI that the builder has been successfully initialized
|
|
252
382
|
// Prevents builder actions to prevent errors caused by missing DOM .
|
|
253
383
|
this.pageBuilderStateStore.setBuilderStarted(true)
|
|
384
|
+
const pagebuilder = document.querySelector('#pagebuilder')
|
|
385
|
+
let validation
|
|
254
386
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
387
|
+
try {
|
|
388
|
+
this.originalComponents = passedComponentsArray
|
|
389
|
+
this.pageBuilderStateStore.setPageBuilderConfig(config)
|
|
390
|
+
// Validate and normalize the config (ensure required fields are present)
|
|
391
|
+
this.#validateConfig(config)
|
|
259
392
|
|
|
260
|
-
|
|
261
|
-
this.pageBuilderStateStore.setPageBuilderConfig(config)
|
|
393
|
+
validation = this.#validateUserProvidedComponents(passedComponentsArray)
|
|
262
394
|
|
|
263
|
-
|
|
264
|
-
|
|
395
|
+
// Update the localStorage key name based on the config/resource
|
|
396
|
+
this.#updateLocalStorageItemName()
|
|
265
397
|
|
|
266
|
-
|
|
267
|
-
|
|
398
|
+
// Page Builder is not Present in the DOM but Components have been passed to the Builder
|
|
399
|
+
if (passedComponentsArray && !pagebuilder) {
|
|
400
|
+
this.#handlePageBuilderNotPresent(passedComponentsArray)
|
|
401
|
+
}
|
|
402
|
+
// Page Builder is Present in the DOM & Components have been passed to the Builder
|
|
403
|
+
if (pagebuilder) {
|
|
404
|
+
this.#completeBuilderInitialization(passedComponentsArray)
|
|
405
|
+
}
|
|
268
406
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
407
|
+
// Return both the success message and validation info if present
|
|
408
|
+
return {
|
|
409
|
+
message: 'Page builder started successfully.',
|
|
410
|
+
...(validation || {}),
|
|
411
|
+
}
|
|
412
|
+
} catch (err) {
|
|
413
|
+
console.error('Not able to start the Page Builder', err)
|
|
414
|
+
this.pageBuilderStateStore.setIsLoadingGlobal(false)
|
|
415
|
+
return {
|
|
416
|
+
error: true as const,
|
|
417
|
+
reason: 'Failed to start the Page Builder due to an unexpected error.',
|
|
418
|
+
}
|
|
272
419
|
}
|
|
273
420
|
}
|
|
274
421
|
|
|
275
|
-
async #completeBuilderInitialization() {
|
|
276
|
-
|
|
277
|
-
const
|
|
278
|
-
|
|
422
|
+
async #completeBuilderInitialization(passedComponentsArray?: BuilderResourceData): Promise<void> {
|
|
423
|
+
this.pageBuilderStateStore.setIsLoadingGlobal(true)
|
|
424
|
+
const localStorageData = this.loadStoredComponentsFromStorage()
|
|
425
|
+
|
|
426
|
+
await this.delay(300)
|
|
279
427
|
|
|
280
428
|
// Deselect any selected or hovered elements in the builder UI
|
|
281
429
|
await this.clearHtmlSelection()
|
|
282
|
-
this.pageBuilderStateStore.setIsLoadingGlobal(true)
|
|
283
|
-
await this.delay(300)
|
|
284
430
|
|
|
285
|
-
|
|
286
|
-
|
|
431
|
+
if (passedComponentsArray) {
|
|
432
|
+
// Prefer components from local storage if available for this resource
|
|
433
|
+
if (!this.pendingMountData && localStorageData && typeof localStorageData === 'string') {
|
|
434
|
+
await this.#updateComponentsFromString(localStorageData)
|
|
435
|
+
} else {
|
|
436
|
+
// If no local storage is found, use the components array provided by the user
|
|
437
|
+
await this.#mountPassedComponentsToDOM(passedComponentsArray)
|
|
438
|
+
this.pendingMountData = null
|
|
439
|
+
}
|
|
440
|
+
}
|
|
287
441
|
|
|
288
|
-
|
|
289
|
-
|
|
442
|
+
//
|
|
443
|
+
//
|
|
444
|
+
//
|
|
445
|
+
if (!passedComponentsArray) {
|
|
446
|
+
// Prefer components from local storage if available for this resource
|
|
447
|
+
if (localStorageData && typeof localStorageData === 'string') {
|
|
448
|
+
await this.#updateComponentsFromString(localStorageData)
|
|
449
|
+
} else {
|
|
450
|
+
// If no local storage is found, use the components array provided by the user
|
|
451
|
+
await this.#mountPassedComponentsToDOM([])
|
|
452
|
+
}
|
|
290
453
|
}
|
|
454
|
+
//
|
|
455
|
+
//
|
|
456
|
+
//
|
|
457
|
+
//
|
|
458
|
+
//
|
|
459
|
+
//
|
|
460
|
+
//
|
|
461
|
+
//
|
|
462
|
+
//
|
|
463
|
+
//
|
|
464
|
+
//
|
|
465
|
+
//
|
|
466
|
+
//
|
|
291
467
|
|
|
292
468
|
// Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
|
|
293
469
|
await nextTick()
|
|
294
470
|
// Attach event listeners to all editable elements in the Builder
|
|
295
471
|
await this.#addListenersToEditableElements()
|
|
472
|
+
// Show a global loading indicator while initializing
|
|
473
|
+
this.pageBuilderStateStore.setIsLoadingGlobal(false)
|
|
296
474
|
|
|
297
475
|
// Clean up any old localStorage items related to previous builder sessions
|
|
298
476
|
this.deleteOldPageBuilderLocalStorage()
|
|
@@ -376,6 +554,8 @@ export class PageBuilderService {
|
|
|
376
554
|
e.preventDefault()
|
|
377
555
|
e.stopPropagation()
|
|
378
556
|
|
|
557
|
+
await this.handleAutoSave()
|
|
558
|
+
|
|
379
559
|
const pagebuilder = document.querySelector('#pagebuilder')
|
|
380
560
|
|
|
381
561
|
if (!pagebuilder) return
|
|
@@ -480,7 +660,7 @@ export class PageBuilderService {
|
|
|
480
660
|
// Deselect any selected or hovered elements in the builder UI
|
|
481
661
|
//
|
|
482
662
|
this.#saveDomComponentsToLocalStorage()
|
|
483
|
-
await this.delay(
|
|
663
|
+
await this.delay(300)
|
|
484
664
|
} catch (err) {
|
|
485
665
|
console.error('Error trying auto save.', err)
|
|
486
666
|
} finally {
|
|
@@ -1113,21 +1293,25 @@ export class PageBuilderService {
|
|
|
1113
1293
|
}
|
|
1114
1294
|
|
|
1115
1295
|
#updateLocalStorageItemName(): void {
|
|
1116
|
-
const
|
|
1296
|
+
const formtype =
|
|
1117
1297
|
this.pageBuilderStateStore.getPageBuilderConfig &&
|
|
1118
1298
|
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
|
|
1119
1299
|
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType
|
|
1120
1300
|
|
|
1121
|
-
const
|
|
1301
|
+
const formname =
|
|
1302
|
+
this.pageBuilderStateStore.getPageBuilderConfig &&
|
|
1303
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
|
|
1304
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formName
|
|
1122
1305
|
|
|
1123
|
-
const
|
|
1124
|
-
this.pageBuilderStateStore.getPageBuilderConfig
|
|
1306
|
+
const resourceData =
|
|
1307
|
+
this.pageBuilderStateStore.getPageBuilderConfig &&
|
|
1308
|
+
this.pageBuilderStateStore.getPageBuilderConfig.resourceData
|
|
1125
1309
|
|
|
1126
1310
|
// Logic for create resource
|
|
1127
|
-
if (
|
|
1128
|
-
if (
|
|
1311
|
+
if (formtype === 'create') {
|
|
1312
|
+
if (formname && formname.length > 0) {
|
|
1129
1313
|
this.pageBuilderStateStore.setLocalStorageItemName(
|
|
1130
|
-
`page-builder-create-resource-${this.sanitizeForLocalStorage(
|
|
1314
|
+
`page-builder-create-resource-${this.sanitizeForLocalStorage(formname)}`,
|
|
1131
1315
|
)
|
|
1132
1316
|
return
|
|
1133
1317
|
}
|
|
@@ -1138,15 +1322,15 @@ export class PageBuilderService {
|
|
|
1138
1322
|
|
|
1139
1323
|
// Logic for create
|
|
1140
1324
|
// Logic for update and with resource form name
|
|
1141
|
-
if (
|
|
1142
|
-
if (typeof
|
|
1325
|
+
if (formtype === 'update') {
|
|
1326
|
+
if (typeof formname === 'string' && formname.length > 0) {
|
|
1143
1327
|
//
|
|
1144
1328
|
//
|
|
1145
1329
|
if (resourceData && resourceData != null && !resourceData.title) {
|
|
1146
1330
|
// Check if id is missing, null, undefined, or an empty string (after trimming)
|
|
1147
1331
|
if (!resourceData.id || typeof resourceData.id === 'string') {
|
|
1148
1332
|
this.pageBuilderStateStore.setLocalStorageItemName(
|
|
1149
|
-
`page-builder-update-resource-${this.sanitizeForLocalStorage(
|
|
1333
|
+
`page-builder-update-resource-${this.sanitizeForLocalStorage(formname)}`,
|
|
1150
1334
|
)
|
|
1151
1335
|
return
|
|
1152
1336
|
}
|
|
@@ -1161,7 +1345,7 @@ export class PageBuilderService {
|
|
|
1161
1345
|
) {
|
|
1162
1346
|
if (!resourceData.id || typeof resourceData.id === 'string') {
|
|
1163
1347
|
this.pageBuilderStateStore.setLocalStorageItemName(
|
|
1164
|
-
`page-builder-update-resource-${this.sanitizeForLocalStorage(
|
|
1348
|
+
`page-builder-update-resource-${this.sanitizeForLocalStorage(formname)}-${this.sanitizeForLocalStorage(resourceData.title)}`,
|
|
1165
1349
|
)
|
|
1166
1350
|
return
|
|
1167
1351
|
}
|
|
@@ -1173,7 +1357,7 @@ export class PageBuilderService {
|
|
|
1173
1357
|
if (!resourceData.title && typeof resourceData.title !== 'string') {
|
|
1174
1358
|
if (resourceData.id || typeof resourceData.id === 'number') {
|
|
1175
1359
|
this.pageBuilderStateStore.setLocalStorageItemName(
|
|
1176
|
-
`page-builder-update-resource-${this.sanitizeForLocalStorage(
|
|
1360
|
+
`page-builder-update-resource-${this.sanitizeForLocalStorage(formname)}-${this.sanitizeForLocalStorage(String(resourceData.id))}`,
|
|
1177
1361
|
)
|
|
1178
1362
|
return
|
|
1179
1363
|
}
|
|
@@ -1189,7 +1373,7 @@ export class PageBuilderService {
|
|
|
1189
1373
|
) {
|
|
1190
1374
|
if (resourceData.id || typeof resourceData.id === 'number') {
|
|
1191
1375
|
this.pageBuilderStateStore.setLocalStorageItemName(
|
|
1192
|
-
`page-builder-update-resource-${this.sanitizeForLocalStorage(
|
|
1376
|
+
`page-builder-update-resource-${this.sanitizeForLocalStorage(formname)}-${this.sanitizeForLocalStorage(resourceData.title)}-${this.sanitizeForLocalStorage(String(resourceData.id))}`,
|
|
1193
1377
|
)
|
|
1194
1378
|
return
|
|
1195
1379
|
}
|
|
@@ -1197,11 +1381,8 @@ export class PageBuilderService {
|
|
|
1197
1381
|
}
|
|
1198
1382
|
}
|
|
1199
1383
|
|
|
1200
|
-
// Logic for update without without
|
|
1201
|
-
if (
|
|
1202
|
-
!resourceFormName ||
|
|
1203
|
-
(typeof resourceFormName === 'string' && resourceFormName.length === 0)
|
|
1204
|
-
) {
|
|
1384
|
+
// Logic for update without without formname
|
|
1385
|
+
if (!formname || (typeof formname === 'string' && formname.length === 0)) {
|
|
1205
1386
|
//
|
|
1206
1387
|
//
|
|
1207
1388
|
if (resourceData && resourceData != null && !resourceData.title) {
|
|
@@ -1304,6 +1485,7 @@ export class PageBuilderService {
|
|
|
1304
1485
|
* Saves the current DOM state (components) to localStorage.
|
|
1305
1486
|
*/
|
|
1306
1487
|
#saveDomComponentsToLocalStorage() {
|
|
1488
|
+
this.#updateLocalStorageItemName()
|
|
1307
1489
|
const pagebuilder = document.querySelector('#pagebuilder')
|
|
1308
1490
|
if (!pagebuilder) return
|
|
1309
1491
|
|
|
@@ -1338,6 +1520,7 @@ export class PageBuilderService {
|
|
|
1338
1520
|
}
|
|
1339
1521
|
|
|
1340
1522
|
async removeCurrentComponentsFromLocalStorage() {
|
|
1523
|
+
this.#updateLocalStorageItemName()
|
|
1341
1524
|
await nextTick()
|
|
1342
1525
|
|
|
1343
1526
|
const key = this.getLocalStorageItemName.value
|
|
@@ -1348,12 +1531,10 @@ export class PageBuilderService {
|
|
|
1348
1531
|
|
|
1349
1532
|
//
|
|
1350
1533
|
deleteOldPageBuilderLocalStorage(): void {
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'update'
|
|
1356
|
-
) {
|
|
1534
|
+
const config = this.pageBuilderStateStore.getPageBuilderConfig
|
|
1535
|
+
const formType = config && config.updateOrCreate && config.updateOrCreate.formType
|
|
1536
|
+
|
|
1537
|
+
if (formType === 'update') {
|
|
1357
1538
|
let oldCountLocalStorages = 0
|
|
1358
1539
|
const deletedItemsLog: { Number: number; Key: string; SavedAt: string }[] = []
|
|
1359
1540
|
|
|
@@ -1401,38 +1582,6 @@ export class PageBuilderService {
|
|
|
1401
1582
|
}
|
|
1402
1583
|
}
|
|
1403
1584
|
|
|
1404
|
-
async hasLocalDraftForUpdate(): Promise<boolean> {
|
|
1405
|
-
const pagebuilder = document.querySelector('#pagebuilder')
|
|
1406
|
-
if (!pagebuilder) {
|
|
1407
|
-
return true
|
|
1408
|
-
}
|
|
1409
|
-
|
|
1410
|
-
if (this.hasStartedEditing) return false
|
|
1411
|
-
|
|
1412
|
-
if (
|
|
1413
|
-
this.pageBuilderStateStore.getPageBuilderConfig &&
|
|
1414
|
-
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
|
|
1415
|
-
typeof this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'string' &&
|
|
1416
|
-
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'update'
|
|
1417
|
-
) {
|
|
1418
|
-
const key = this.getLocalStorageItemName.value
|
|
1419
|
-
if (typeof key === 'string') {
|
|
1420
|
-
const draft = localStorage.getItem(key)
|
|
1421
|
-
if (draft) {
|
|
1422
|
-
try {
|
|
1423
|
-
await this.delay(500)
|
|
1424
|
-
this.pageBuilderStateStore.setHasLocalDraftForUpdate(false)
|
|
1425
|
-
return true
|
|
1426
|
-
} catch (err) {
|
|
1427
|
-
console.error('Unable to mount components to DOM.', err)
|
|
1428
|
-
return false
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
return false
|
|
1434
|
-
}
|
|
1435
|
-
|
|
1436
1585
|
// Call this when the user starts editing (e.g., on first change or when resuming a draft)
|
|
1437
1586
|
startEditing() {
|
|
1438
1587
|
this.hasStartedEditing = true
|
|
@@ -1440,40 +1589,49 @@ export class PageBuilderService {
|
|
|
1440
1589
|
|
|
1441
1590
|
//
|
|
1442
1591
|
async resumeEditingForUpdate() {
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1592
|
+
this.#updateLocalStorageItemName()
|
|
1593
|
+
const config = this.pageBuilderStateStore.getPageBuilderConfig
|
|
1594
|
+
const formType = config && config.updateOrCreate && config.updateOrCreate.formType
|
|
1595
|
+
|
|
1596
|
+
if (formType !== 'update') return
|
|
1597
|
+
//
|
|
1598
|
+
//
|
|
1599
|
+
//
|
|
1450
1600
|
|
|
1451
|
-
|
|
1452
|
-
const updateDraftFromLocalStorage = localStorage.getItem(key)
|
|
1601
|
+
const key = this.getLocalStorageItemName.value
|
|
1453
1602
|
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1603
|
+
if (typeof key === 'string') {
|
|
1604
|
+
const updateDraftFromLocalStorage = localStorage.getItem(key)
|
|
1605
|
+
|
|
1606
|
+
if (typeof updateDraftFromLocalStorage === 'string') {
|
|
1607
|
+
this.pageBuilderStateStore.setIsLoadingResumeEditing(true)
|
|
1608
|
+
await delay(300)
|
|
1609
|
+
await this.#updateComponentsFromString(updateDraftFromLocalStorage)
|
|
1610
|
+
this.pageBuilderStateStore.setIsLoadingResumeEditing(false)
|
|
1460
1611
|
}
|
|
1461
1612
|
}
|
|
1613
|
+
|
|
1614
|
+
// Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
|
|
1615
|
+
await nextTick()
|
|
1616
|
+
// Attach event listeners to all editable elements in the Builder
|
|
1617
|
+
await this.#addListenersToEditableElements()
|
|
1618
|
+
// set loading to false
|
|
1619
|
+
this.pageBuilderStateStore.setIsLoadingResumeEditing(false)
|
|
1462
1620
|
}
|
|
1463
1621
|
|
|
1464
1622
|
async restoreOriginalContent() {
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
) {
|
|
1623
|
+
this.#updateLocalStorageItemName()
|
|
1624
|
+
const config = this.pageBuilderStateStore.getPageBuilderConfig
|
|
1625
|
+
const formType = config && config.updateOrCreate && config.updateOrCreate.formType
|
|
1626
|
+
|
|
1627
|
+
if (formType === 'update') {
|
|
1471
1628
|
this.pageBuilderStateStore.setIsRestoring(true)
|
|
1472
1629
|
await this.delay(300)
|
|
1473
1630
|
|
|
1474
1631
|
// Restore the original content if available
|
|
1475
|
-
if (this.originalComponents) {
|
|
1476
|
-
this
|
|
1632
|
+
if (Array.isArray(this.originalComponents)) {
|
|
1633
|
+
await this.#mountPassedComponentsToDOM(this.originalComponents)
|
|
1634
|
+
this.removeCurrentComponentsFromLocalStorage()
|
|
1477
1635
|
}
|
|
1478
1636
|
|
|
1479
1637
|
// Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
|
|
@@ -1490,6 +1648,7 @@ export class PageBuilderService {
|
|
|
1490
1648
|
}
|
|
1491
1649
|
|
|
1492
1650
|
loadStoredComponentsFromStorage() {
|
|
1651
|
+
this.#updateLocalStorageItemName()
|
|
1493
1652
|
if (!this.getLocalStorageItemName.value) return false
|
|
1494
1653
|
|
|
1495
1654
|
if (
|
|
@@ -1784,19 +1943,22 @@ export class PageBuilderService {
|
|
|
1784
1943
|
* @param data - JSON string (e.g., '[{"html_code":"...","id":"123","title":"..."}]')
|
|
1785
1944
|
* OR HTML string (e.g., '<section data-componentid="123">...</section>')
|
|
1786
1945
|
*/
|
|
1787
|
-
async #
|
|
1946
|
+
async #updateComponentsFromString(htmlString: string): Promise<void> {
|
|
1788
1947
|
// Auto-detect if input is JSON or HTML
|
|
1789
1948
|
const trimmedData = htmlString.trim()
|
|
1790
1949
|
|
|
1791
1950
|
if (trimmedData.startsWith('[') || trimmedData.startsWith('{')) {
|
|
1792
1951
|
// Looks like JSON - parse as JSON
|
|
1793
1952
|
await this.#parseJSONComponents(trimmedData)
|
|
1794
|
-
|
|
1953
|
+
return
|
|
1954
|
+
}
|
|
1955
|
+
if (trimmedData.startsWith('<')) {
|
|
1795
1956
|
// Looks like HTML - parse as HTML
|
|
1796
1957
|
await this.#parseHTMLComponents(trimmedData)
|
|
1797
|
-
|
|
1798
|
-
await this.#parseJSONComponents(trimmedData)
|
|
1958
|
+
return
|
|
1799
1959
|
}
|
|
1960
|
+
|
|
1961
|
+
await this.#parseJSONComponents(trimmedData)
|
|
1800
1962
|
}
|
|
1801
1963
|
|
|
1802
1964
|
// Private method to parse JSON components and save pageBuilderContentSavedAt to localStorage
|
|
@@ -1917,145 +2079,6 @@ export class PageBuilderService {
|
|
|
1917
2079
|
}
|
|
1918
2080
|
}
|
|
1919
2081
|
|
|
1920
|
-
async mountComponentsToDOM(passedData: string): Promise<void> {
|
|
1921
|
-
const config = this.pageBuilderStateStore.getPageBuilderConfig
|
|
1922
|
-
const formType = config && config.updateOrCreate && config.updateOrCreate.formType
|
|
1923
|
-
|
|
1924
|
-
if (formType) {
|
|
1925
|
-
const pagebuilder = document.querySelector('#pagebuilder')
|
|
1926
|
-
const localStorageData = this.loadStoredComponentsFromStorage()
|
|
1927
|
-
|
|
1928
|
-
if (!pagebuilder) {
|
|
1929
|
-
await this.#handlePageBuilderNotPresent(passedData, formType)
|
|
1930
|
-
return
|
|
1931
|
-
}
|
|
1932
|
-
|
|
1933
|
-
this.#handleOriginalComponentsForUpdate(passedData, formType)
|
|
1934
|
-
|
|
1935
|
-
if (this.#isCreateFormType(formType)) {
|
|
1936
|
-
await this.#handleCreateFormType(passedData, localStorageData)
|
|
1937
|
-
return
|
|
1938
|
-
}
|
|
1939
|
-
|
|
1940
|
-
if (this.#isUpdateFormType(formType)) {
|
|
1941
|
-
await this.#handleUpdateFormType(passedData, localStorageData)
|
|
1942
|
-
return
|
|
1943
|
-
}
|
|
1944
|
-
}
|
|
1945
|
-
}
|
|
1946
|
-
|
|
1947
|
-
// --- Private helpers ---
|
|
1948
|
-
|
|
1949
|
-
async #handlePageBuilderNotPresent(passedData: string, formType: string) {
|
|
1950
|
-
if (formType === 'create') {
|
|
1951
|
-
console.log('mountComponentsToDOM ran: m0')
|
|
1952
|
-
this.pendingMountData = ''
|
|
1953
|
-
return
|
|
1954
|
-
}
|
|
1955
|
-
console.log('mountComponentsToDOM ran: m1:')
|
|
1956
|
-
this.pendingMountData = passedData
|
|
1957
|
-
}
|
|
1958
|
-
|
|
1959
|
-
#handleOriginalComponentsForUpdate(passedData: string, formType: string) {
|
|
1960
|
-
if (formType === 'update' && passedData && !this.originalComponents) {
|
|
1961
|
-
console.log('mountComponentsToDOM ran: m3')
|
|
1962
|
-
this.originalComponents = passedData
|
|
1963
|
-
}
|
|
1964
|
-
}
|
|
1965
|
-
|
|
1966
|
-
async #handleUpdateFormType(passedData: string, localStorageData: string | false) {
|
|
1967
|
-
if (passedData) {
|
|
1968
|
-
console.log('mountComponentsToDOM ran: m4')
|
|
1969
|
-
await this.#setComponentsFromData(passedData)
|
|
1970
|
-
return
|
|
1971
|
-
}
|
|
1972
|
-
if (localStorageData) {
|
|
1973
|
-
console.log('mountComponentsToDOM ran: m5')
|
|
1974
|
-
await this.#setComponentsFromData(localStorageData)
|
|
1975
|
-
return
|
|
1976
|
-
}
|
|
1977
|
-
// If nothing, clear components
|
|
1978
|
-
console.log('mountComponentsToDOM ran: m6')
|
|
1979
|
-
this.deleteAllComponentsFromDOM()
|
|
1980
|
-
}
|
|
1981
|
-
|
|
1982
|
-
async #handleCreateFormType(passedData: string, localStorageData: string | false) {
|
|
1983
|
-
if (localStorageData) {
|
|
1984
|
-
console.log('mountComponentsToDOM ran: m7')
|
|
1985
|
-
await this.#setComponentsFromData(localStorageData)
|
|
1986
|
-
return
|
|
1987
|
-
}
|
|
1988
|
-
if (passedData) {
|
|
1989
|
-
console.log('mountComponentsToDOM ran: m8')
|
|
1990
|
-
await this.#setComponentsFromData(passedData)
|
|
1991
|
-
return
|
|
1992
|
-
}
|
|
1993
|
-
}
|
|
1994
|
-
|
|
1995
|
-
#isCreateFormType(formType: string): boolean {
|
|
1996
|
-
return formType === 'create'
|
|
1997
|
-
}
|
|
1998
|
-
|
|
1999
|
-
#isUpdateFormType(formType: string): boolean {
|
|
2000
|
-
return formType === 'update'
|
|
2001
|
-
}
|
|
2002
|
-
|
|
2003
|
-
async ensureBuilderInitializedForCreate() {
|
|
2004
|
-
const pagebuilder = document.querySelector('#pagebuilder')
|
|
2005
|
-
if (!pagebuilder) return
|
|
2006
|
-
|
|
2007
|
-
const config = this.pageBuilderStateStore.getPageBuilderConfig
|
|
2008
|
-
console.log('den er:', config)
|
|
2009
|
-
const formType = config && config.updateOrCreate && config.updateOrCreate.formType
|
|
2010
|
-
|
|
2011
|
-
if (formType === 'create') {
|
|
2012
|
-
this.#completeBuilderInitialization()
|
|
2013
|
-
await nextTick()
|
|
2014
|
-
|
|
2015
|
-
if (
|
|
2016
|
-
formType === 'create' &&
|
|
2017
|
-
(!this.getComponents.value ||
|
|
2018
|
-
(Array.isArray(this.getComponents.value) && this.getComponents.value.length === 0))
|
|
2019
|
-
) {
|
|
2020
|
-
console.log('ensureBuilderInitializedForCreate e1')
|
|
2021
|
-
await this.mountComponentsToDOM('')
|
|
2022
|
-
this.pendingMountData = null
|
|
2023
|
-
return
|
|
2024
|
-
}
|
|
2025
|
-
|
|
2026
|
-
console.log('ensureBuilderInitializedForCreate e2:')
|
|
2027
|
-
await this.mountComponentsToDOM('')
|
|
2028
|
-
await nextTick()
|
|
2029
|
-
// Attach event listeners to all editable elements in the Builder
|
|
2030
|
-
await this.#addListenersToEditableElements()
|
|
2031
|
-
}
|
|
2032
|
-
}
|
|
2033
|
-
|
|
2034
|
-
async ensureBuilderInitializedForUpdate() {
|
|
2035
|
-
const pagebuilder = document.querySelector('#pagebuilder')
|
|
2036
|
-
if (!pagebuilder) return
|
|
2037
|
-
|
|
2038
|
-
const config = this.pageBuilderStateStore.getPageBuilderConfig
|
|
2039
|
-
const formType = config && config.updateOrCreate && config.updateOrCreate.formType
|
|
2040
|
-
|
|
2041
|
-
if (formType === 'update') {
|
|
2042
|
-
this.#completeBuilderInitialization()
|
|
2043
|
-
|
|
2044
|
-
// Only for update/draft/demo: mount if pendingMountData is a non-empty string
|
|
2045
|
-
if (this.pendingMountData && typeof this.pendingMountData === 'string') {
|
|
2046
|
-
console.log('ensureBuilderInitializedForUpdate t1:')
|
|
2047
|
-
await this.mountComponentsToDOM(this.pendingMountData)
|
|
2048
|
-
this.pendingMountData = null
|
|
2049
|
-
return
|
|
2050
|
-
}
|
|
2051
|
-
|
|
2052
|
-
console.log('ensureBuilderInitializedForUpdate t2:')
|
|
2053
|
-
await nextTick()
|
|
2054
|
-
// Always try to load latest from localStorage or fallback
|
|
2055
|
-
await this.mountComponentsToDOM('')
|
|
2056
|
-
}
|
|
2057
|
-
}
|
|
2058
|
-
|
|
2059
2082
|
async toggleTipTapModal(status: boolean): Promise<void> {
|
|
2060
2083
|
this.pageBuilderStateStore.setShowModalTipTap(status)
|
|
2061
2084
|
|