@myissue/vue-website-page-builder 3.3.64 → 3.3.65

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.
Files changed (32) hide show
  1. package/README.md +147 -126
  2. package/dist/logo/mybuilder_new_lowercase.svg +17558 -0
  3. package/dist/vue-website-page-builder.css +1 -1
  4. package/dist/vue-website-page-builder.js +7326 -6943
  5. package/dist/vue-website-page-builder.umd.cjs +54 -51
  6. package/package.json +2 -2
  7. package/src/Components/DemoUnsplash.vue +1 -4
  8. package/src/Components/PageBuilder/EditorMenu/Editables/BackgroundColorEditor.vue +2 -1
  9. package/src/Components/PageBuilder/EditorMenu/Editables/BorderRadius.vue +18 -5
  10. package/src/Components/PageBuilder/EditorMenu/Editables/Borders.vue +6 -4
  11. package/src/Components/PageBuilder/EditorMenu/Editables/ClassEditor.vue +2 -1
  12. package/src/Components/PageBuilder/EditorMenu/Editables/EditGetElement.vue +5 -5
  13. package/src/Components/PageBuilder/EditorMenu/Editables/ManageBackgroundOpacity.vue +7 -8
  14. package/src/Components/PageBuilder/EditorMenu/Editables/ManageOpacity.vue +2 -2
  15. package/src/Components/PageBuilder/EditorMenu/Editables/Margin.vue +4 -2
  16. package/src/Components/PageBuilder/EditorMenu/Editables/Padding.vue +4 -2
  17. package/src/Components/PageBuilder/EditorMenu/Editables/StyleEditor.vue +115 -0
  18. package/src/Components/PageBuilder/EditorMenu/Editables/TextColorEditor.vue +2 -1
  19. package/src/Components/PageBuilder/EditorMenu/Editables/Typography.vue +14 -7
  20. package/src/Components/PageBuilder/EditorMenu/RightSidebarEditor.vue +56 -64
  21. package/src/Components/PageBuilder/ToolbarOption/ToolbarOption.vue +10 -7
  22. package/src/PageBuilder/PageBuilder.vue +89 -63
  23. package/src/PageBuilder/Preview.vue +25 -9
  24. package/src/composables/extractCleanHTMLFromPageBuilder.ts +4 -3
  25. package/src/css/app.css +10 -70
  26. package/src/services/LocalStorageManager.ts +1 -162
  27. package/src/services/PageBuilderService.ts +584 -265
  28. package/src/stores/page-builder-state.ts +8 -0
  29. package/src/tests/PageBuilderTest.vue +20 -19
  30. package/src/tests/componentsArray.test.json +3 -3
  31. package/src/types/index.ts +10 -2
  32. package/src/utils/html-elements/component.ts +10 -10
@@ -1,11 +1,9 @@
1
- import { LocalStorageManager } from './LocalStorageManager'
2
-
3
- // Type definitions
4
1
  import type {
5
2
  BuilderResourceData,
6
3
  ComponentObject,
7
4
  ImageObject,
8
5
  PageBuilderConfig,
6
+ PageSettings,
9
7
  StartBuilderResult,
10
8
  } from '../types'
11
9
  import type { usePageBuilderStateStore } from '../stores/page-builder-state'
@@ -44,26 +42,20 @@ export class PageBuilderService {
44
42
  private hasStartedEditing: boolean = false
45
43
  // Hold data from Database or Backend for updated post
46
44
  private originalComponents: BuilderResourceData | undefined = undefined
47
- // Holds data to be mounted when #pagebuilder is not yet present in the DOM
48
- private pendingMountData: BuilderResourceData | null = null
45
+ // Holds data to be mounted when pagebuilder is not yet present in the DOM
46
+ private savedMountComponents: BuilderResourceData | null = null
47
+ private pendingMountComponents: BuilderResourceData | null = null
49
48
  private isPageBuilderMissingOnStart: boolean = false
50
- private localStorageManager: LocalStorageManager
51
49
 
52
50
  constructor(pageBuilderStateStore: ReturnType<typeof usePageBuilderStateStore>) {
53
- this.localStorageManager = new LocalStorageManager(
54
- pageBuilderStateStore,
55
- this.sanitizeForLocalStorage,
56
- )
57
51
  this.hasStartedEditing = false
58
52
  this.pageBuilderStateStore = pageBuilderStateStore
59
-
60
- this.getLocalStorageItemName = computed(
61
- () => this.pageBuilderStateStore.getLocalStorageItemName,
62
- )
63
-
64
53
  this.getApplyImageToSelection = computed(
65
54
  () => this.pageBuilderStateStore.getApplyImageToSelection,
66
55
  )
56
+ this.getLocalStorageItemName = computed(
57
+ () => this.pageBuilderStateStore.getLocalStorageItemName,
58
+ )
67
59
  this.getHyberlinkEnable = computed(() => this.pageBuilderStateStore.getHyberlinkEnable)
68
60
  this.getComponents = computed(() => this.pageBuilderStateStore.getComponents)
69
61
 
@@ -97,6 +89,14 @@ export class PageBuilderService {
97
89
  'SPAN',
98
90
  'BLOCKQUOTE',
99
91
  'BR',
92
+ 'PRE',
93
+ 'CODE',
94
+ 'MARK',
95
+ 'DEL',
96
+ 'INS',
97
+ 'U',
98
+ 'FIGURE',
99
+ 'FIGCAPTION',
100
100
  ]
101
101
  }
102
102
 
@@ -104,10 +104,10 @@ export class PageBuilderService {
104
104
  async clearHtmlSelection(): Promise<void> {
105
105
  this.pageBuilderStateStore.setComponent(null)
106
106
  this.pageBuilderStateStore.setElement(null)
107
- await this.#removeHoveredAndSelected()
107
+ await this.removeHoveredAndSelected()
108
108
  }
109
109
 
110
- #ensureUpdateOrCreateConfig(config: PageBuilderConfig): void {
110
+ private ensureUpdateOrCreateConfig(config: PageBuilderConfig): void {
111
111
  // Case A: updateOrCreate is missing or an empty object
112
112
  if (!config.updateOrCreate || (config.updateOrCreate && isEmptyObject(config.updateOrCreate))) {
113
113
  const updatedConfig = {
@@ -183,7 +183,7 @@ export class PageBuilderService {
183
183
  }
184
184
  }
185
185
 
186
- #validateUserProvidedComponents(components: unknown) {
186
+ private validateUserProvidedComponents(components: unknown) {
187
187
  const formType =
188
188
  this.pageBuilderStateStore.getPageBuilderConfig &&
189
189
  this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
@@ -235,7 +235,7 @@ export class PageBuilderService {
235
235
  return
236
236
  }
237
237
 
238
- #validateConfig(config: PageBuilderConfig): void {
238
+ private validateConfig(config: PageBuilderConfig): void {
239
239
  const defaultConfigValues = {
240
240
  updateOrCreate: {
241
241
  formType: 'create',
@@ -249,7 +249,7 @@ export class PageBuilderService {
249
249
  }
250
250
 
251
251
  if (config && Object.keys(config).length !== 0 && config.constructor === Object) {
252
- this.#ensureUpdateOrCreateConfig(config)
252
+ this.ensureUpdateOrCreateConfig(config)
253
253
  }
254
254
  }
255
255
 
@@ -272,24 +272,26 @@ export class PageBuilderService {
272
272
  this.pageBuilderStateStore.setBuilderStarted(true)
273
273
  const pagebuilder = document.querySelector('#pagebuilder')
274
274
  let validation
275
-
276
275
  try {
277
276
  this.originalComponents = passedComponentsArray
278
277
  this.pageBuilderStateStore.setPageBuilderConfig(config)
279
278
  // Validate and normalize the config (ensure required fields are present)
280
- this.#validateConfig(config)
279
+ this.validateConfig(config)
281
280
 
282
- validation = this.#validateUserProvidedComponents(passedComponentsArray)
281
+ validation = this.validateUserProvidedComponents(passedComponentsArray)
283
282
 
284
283
  // Update the localStorage key name based on the config/resource
285
- this.localStorageManager.updateLocalStorageItemName()
284
+ this.updateLocalStorageItemName()
286
285
 
286
+ if (passedComponentsArray) {
287
+ this.savedMountComponents = passedComponentsArray
288
+ }
287
289
  // Page Builder is not Present in the DOM but Components have been passed to the Builder
288
290
  if (!pagebuilder) {
289
291
  this.isPageBuilderMissingOnStart = true
290
292
  }
291
293
  if (passedComponentsArray && !pagebuilder) {
292
- this.pendingMountData = passedComponentsArray
294
+ this.pendingMountComponents = passedComponentsArray
293
295
  }
294
296
  // Page Builder is Present in the DOM & Components have been passed to the Builder
295
297
  if (pagebuilder) {
@@ -297,9 +299,7 @@ export class PageBuilderService {
297
299
  }
298
300
 
299
301
  // result to end user
300
-
301
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
302
- const result: any = {
302
+ const result: StartBuilderResult = {
303
303
  message: 'Page builder started successfully.',
304
304
  }
305
305
 
@@ -307,7 +307,7 @@ export class PageBuilderService {
307
307
  result.validation = validation
308
308
  }
309
309
 
310
- // passedComponentsArray
310
+ // PassedComponentsArray
311
311
  if (Array.isArray(passedComponentsArray) && passedComponentsArray.length >= 0) {
312
312
  result.passedComponentsArray = passedComponentsArray
313
313
  }
@@ -323,7 +323,10 @@ export class PageBuilderService {
323
323
  }
324
324
  }
325
325
 
326
- async completeBuilderInitialization(passedComponentsArray?: BuilderResourceData): Promise<void> {
326
+ async completeBuilderInitialization(
327
+ passedComponentsArray?: BuilderResourceData,
328
+ internalPageBuilderCall?: boolean,
329
+ ): Promise<void> {
327
330
  this.pageBuilderStateStore.setIsLoadingGlobal(true)
328
331
  await delay(400)
329
332
 
@@ -333,63 +336,78 @@ export class PageBuilderService {
333
336
  const config = this.pageBuilderStateStore.getPageBuilderConfig
334
337
  const formType = config && config.updateOrCreate && config.updateOrCreate.formType
335
338
 
336
- const localStorageData = this.loadStoredComponentsFromStorage()
339
+ const localStorageData = this.getSavedPageHtml()
337
340
 
338
341
  // Deselect any selected or hovered elements in the builder UI
339
342
  await this.clearHtmlSelection()
340
343
 
341
- //
342
344
  if (formType === 'update' || formType === 'create') {
343
- if (!this.pendingMountData) {
344
- //
345
- //
346
- if (!passedComponentsArray && !this.isPageBuilderMissingOnStart && localStorageData) {
347
- await this.#completeMountProcess(localStorageData)
345
+ if (!this.pendingMountComponents) {
346
+ // Page Builder Is initially present in DOM
347
+ if (!passedComponentsArray && this.isPageBuilderMissingOnStart && localStorageData) {
348
+ console.log('1111:', internalPageBuilderCall)
349
+ await this.completeMountProcess(localStorageData)
348
350
  return
349
351
  }
350
352
  if (passedComponentsArray && !localStorageData) {
351
- await this.#completeMountProcess(JSON.stringify(passedComponentsArray), true)
353
+ console.log('2222:', internalPageBuilderCall)
354
+ await this.completeMountProcess(JSON.stringify(passedComponentsArray), true)
355
+ this.saveDomComponentsToLocalStorage()
352
356
  return
353
357
  }
354
358
 
355
359
  if (passedComponentsArray && localStorageData) {
360
+ console.log('3333:', internalPageBuilderCall)
356
361
  this.pageBuilderStateStore.setHasLocalDraftForUpdate(true)
357
-
358
- await this.#completeMountProcess(JSON.stringify(passedComponentsArray), true)
362
+ await this.completeMountProcess(JSON.stringify(passedComponentsArray), true)
359
363
  return
360
364
  }
361
-
362
- if (!passedComponentsArray && localStorageData && this.isPageBuilderMissingOnStart) {
363
- await this.#completeMountProcess(localStorageData)
365
+ if (!passedComponentsArray && localStorageData && !this.savedMountComponents) {
366
+ console.log('4444:', internalPageBuilderCall)
367
+ await this.completeMountProcess(localStorageData)
368
+ return
369
+ }
370
+ if (!passedComponentsArray && this.savedMountComponents && localStorageData) {
371
+ console.log('5555:', internalPageBuilderCall)
372
+ await this.completeMountProcess(JSON.stringify(this.savedMountComponents))
364
373
  return
365
374
  }
366
375
 
367
376
  if (!passedComponentsArray && !localStorageData && this.isPageBuilderMissingOnStart) {
368
- await this.#completeMountProcess(JSON.stringify([]))
377
+ console.log('6666:', internalPageBuilderCall)
378
+ await this.completeMountProcess(JSON.stringify([]))
369
379
  return
370
380
  }
371
381
 
372
382
  if (!this.isPageBuilderMissingOnStart && !localStorageData && !passedComponentsArray) {
373
- await this.#completeMountProcess(JSON.stringify([]))
383
+ console.log('7777:', internalPageBuilderCall)
384
+ await this.completeMountProcess(JSON.stringify([]))
374
385
  return
375
386
  }
376
387
  }
377
388
 
378
- // FOCUS ON: pendingMountData
379
- if (this.pendingMountData) {
389
+ // FOCUS ON: pendingMountComponents
390
+ if (this.pendingMountComponents) {
391
+ // No Page Builder Is present in DOM initially
380
392
  if (localStorageData && this.isPageBuilderMissingOnStart) {
393
+ console.log('8888:', internalPageBuilderCall)
394
+ await this.completeMountProcess(JSON.stringify(this.pendingMountComponents), true)
395
+ await delay(3000)
381
396
  this.pageBuilderStateStore.setHasLocalDraftForUpdate(true)
382
- await this.#completeMountProcess(JSON.stringify(this.pendingMountData), true)
383
- this.pendingMountData = null
397
+ this.pendingMountComponents = null
384
398
  return
385
399
  }
386
400
  if (!localStorageData && passedComponentsArray && this.isPageBuilderMissingOnStart) {
387
- await this.#completeMountProcess(JSON.stringify(this.pendingMountData), true)
401
+ console.log('9999:', internalPageBuilderCall)
402
+ await this.completeMountProcess(JSON.stringify(this.pendingMountComponents), true)
403
+ this.saveDomComponentsToLocalStorage()
388
404
  return
389
405
  }
390
406
 
391
407
  if (!passedComponentsArray && !localStorageData && this.isPageBuilderMissingOnStart) {
392
- await this.#completeMountProcess(JSON.stringify(this.pendingMountData), true)
408
+ console.log('10000:', internalPageBuilderCall)
409
+ await this.completeMountProcess(JSON.stringify(this.pendingMountComponents), true)
410
+ this.saveDomComponentsToLocalStorage()
393
411
  return
394
412
  }
395
413
  }
@@ -397,21 +415,22 @@ export class PageBuilderService {
397
415
  //
398
416
  }
399
417
 
400
- async #completeMountProcess(html: string, usePassedPageSettings?: boolean) {
401
- await this.#mountComponentsToDOM(html, usePassedPageSettings)
402
- // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
403
- await nextTick()
404
- // Attach event listeners to all editable elements in the Builder
405
- await this.#addListenersToEditableElements()
418
+ private async completeMountProcess(html: string, usePassedPageSettings?: boolean) {
419
+ await this.mountComponentsToDOM(html, usePassedPageSettings)
406
420
 
407
421
  // Clean up any old localStorage items related to previous builder sessions
408
422
  this.deleteOldPageBuilderLocalStorage()
409
423
 
410
424
  this.pageBuilderStateStore.setIsRestoring(false)
411
425
  this.pageBuilderStateStore.setIsLoadingGlobal(false)
426
+
427
+ // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
428
+ await nextTick()
429
+ // Attach event listeners to all editable elements in the Builder
430
+ await this.addListenersToEditableElements()
412
431
  }
413
432
 
414
- #applyElementClassChanges(
433
+ private applyElementClassChanges(
415
434
  cssUserSelection: string | undefined,
416
435
  CSSArray: string[],
417
436
  mutationName: string,
@@ -461,7 +480,7 @@ export class PageBuilderService {
461
480
  return currentCSS
462
481
  }
463
482
 
464
- async clearClassesFromPage() {
483
+ public async clearClassesFromPage() {
465
484
  const pagebuilder = document.querySelector('#pagebuilder')
466
485
  if (!pagebuilder) return
467
486
 
@@ -470,7 +489,7 @@ export class PageBuilderService {
470
489
  this.initializeElementStyles()
471
490
  await nextTick()
472
491
  }
473
- async clearInlineStylesFromPagee() {
492
+ public async clearInlineStylesFromPagee() {
474
493
  const pagebuilder = document.querySelector('#pagebuilder')
475
494
  if (!pagebuilder) return
476
495
 
@@ -480,7 +499,7 @@ export class PageBuilderService {
480
499
  await nextTick()
481
500
  }
482
501
 
483
- async globalPageStyles() {
502
+ public async globalPageStyles() {
484
503
  const pagebuilder = document.querySelector('#pagebuilder')
485
504
  if (!pagebuilder) return
486
505
 
@@ -496,19 +515,19 @@ export class PageBuilderService {
496
515
  await nextTick()
497
516
  }
498
517
 
499
- handleFontWeight(userSelectedFontWeight?: string): void {
500
- this.#applyElementClassChanges(
518
+ public handleFontWeight(userSelectedFontWeight?: string): void {
519
+ this.applyElementClassChanges(
501
520
  userSelectedFontWeight,
502
521
  tailwindFontStyles.fontWeight,
503
522
  'setFontWeight',
504
523
  )
505
524
  }
506
525
 
507
- handleFontSizeBase(userSelectedFontSize?: string): void {
508
- this.#applyElementClassChanges(userSelectedFontSize, tailwindFontSizes.fontBase, 'setFontBase')
526
+ public handleFontSizeBase(userSelectedFontSize?: string): void {
527
+ this.applyElementClassChanges(userSelectedFontSize, tailwindFontSizes.fontBase, 'setFontBase')
509
528
  }
510
529
 
511
- handleFontSizeDesktop(userSelectedFontSize?: string): void {
530
+ public handleFontSizeDesktop(userSelectedFontSize?: string): void {
512
531
  const currentHTMLElement = this.getElement.value
513
532
  if (!currentHTMLElement) return
514
533
 
@@ -563,12 +582,8 @@ export class PageBuilderService {
563
582
  }
564
583
  }
565
584
 
566
- #applyHelperCSSToElements(element: HTMLElement): void {
567
- this.#wrapElementInDivIfExcluded(element)
568
-
569
- if (element.tagName === 'IMG') {
570
- element.classList.add('smooth-transition')
571
- }
585
+ private applyHelperCSSToElements(element: HTMLElement): void {
586
+ this.wrapElementInDivIfExcluded(element)
572
587
 
573
588
  // If this is a DIV and its only/main child is a heading, apply font size classes to the DIV
574
589
  if (
@@ -594,20 +609,20 @@ export class PageBuilderService {
594
609
  }
595
610
  }
596
611
 
597
- async toggleTipTapModal(status: boolean): Promise<void> {
612
+ public async toggleTipTapModal(status: boolean): Promise<void> {
598
613
  this.pageBuilderStateStore.setShowModalTipTap(status)
599
614
 
600
615
  // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
601
616
  await nextTick()
602
617
  // Attach event listeners to all editable elements in the Builder
603
- await this.#addListenersToEditableElements()
618
+ await this.addListenersToEditableElements()
604
619
 
605
620
  if (!status) {
606
621
  await this.handleAutoSave()
607
622
  }
608
623
  }
609
624
 
610
- #wrapElementInDivIfExcluded(element: HTMLElement): void {
625
+ private wrapElementInDivIfExcluded(element: HTMLElement): void {
611
626
  if (!element) return
612
627
 
613
628
  if (
@@ -621,7 +636,7 @@ export class PageBuilderService {
621
636
  }
622
637
  }
623
638
 
624
- #handleElementClick = async (e: Event, element: HTMLElement): Promise<void> => {
639
+ private handleElementClick = async (e: Event, element: HTMLElement): Promise<void> => {
625
640
  e.preventDefault()
626
641
  e.stopPropagation()
627
642
 
@@ -645,7 +660,7 @@ export class PageBuilderService {
645
660
  this.pageBuilderStateStore.setElement(element)
646
661
  }
647
662
 
648
- #handleMouseOver = (e: Event, element: HTMLElement): void => {
663
+ private handleMouseOver = (e: Event, element: HTMLElement): void => {
649
664
  e.preventDefault()
650
665
  e.stopPropagation()
651
666
 
@@ -663,7 +678,7 @@ export class PageBuilderService {
663
678
  }
664
679
  }
665
680
 
666
- #handleMouseLeave = (e: Event): void => {
681
+ private handleMouseLeave = (e: Event): void => {
667
682
  e.preventDefault()
668
683
  e.stopPropagation()
669
684
 
@@ -676,7 +691,7 @@ export class PageBuilderService {
676
691
  }
677
692
  }
678
693
 
679
- isEditableElement(el: Element | null): boolean {
694
+ public isEditableElement(el: Element | null): boolean {
680
695
  if (!el) return false
681
696
  return !this.NoneListernesTags.includes(el.tagName)
682
697
  }
@@ -685,7 +700,7 @@ export class PageBuilderService {
685
700
  * The function is used to
686
701
  * attach event listeners to each element within a 'section'
687
702
  */
688
- #addListenersToEditableElements = async () => {
703
+ private addListenersToEditableElements = async () => {
689
704
  const elementsWithListeners = new WeakSet<Element>()
690
705
 
691
706
  const pagebuilder = document.querySelector('#pagebuilder')
@@ -702,9 +717,9 @@ export class PageBuilderService {
702
717
  // Type assertion to HTMLElement since we know these are DOM elements
703
718
  const htmlElement = element as HTMLElement
704
719
  // Attach event listeners directly to individual elements
705
- htmlElement.addEventListener('click', (e) => this.#handleElementClick(e, htmlElement))
706
- htmlElement.addEventListener('mouseover', (e) => this.#handleMouseOver(e, htmlElement))
707
- htmlElement.addEventListener('mouseleave', (e) => this.#handleMouseLeave(e))
720
+ htmlElement.addEventListener('click', (e) => this.handleElementClick(e, htmlElement))
721
+ htmlElement.addEventListener('mouseover', (e) => this.handleMouseOver(e, htmlElement))
722
+ htmlElement.addEventListener('mouseleave', (e) => this.handleMouseLeave(e))
708
723
  }
709
724
  }
710
725
 
@@ -712,7 +727,7 @@ export class PageBuilderService {
712
727
  })
713
728
  }
714
729
 
715
- handleAutoSave = async () => {
730
+ public handleAutoSave = async () => {
716
731
  this.startEditing()
717
732
  const passedConfig = this.pageBuilderStateStore.getPageBuilderConfig
718
733
 
@@ -730,7 +745,7 @@ export class PageBuilderService {
730
745
  this.pageBuilderStateStore.setIsSaving(true)
731
746
  // Deselect any selected or hovered elements in the builder UI
732
747
  //
733
- this.#saveDomComponentsToLocalStorage()
748
+ this.saveDomComponentsToLocalStorage()
734
749
  await delay(400)
735
750
  } catch (err) {
736
751
  console.error('Error trying auto save.', err)
@@ -742,7 +757,7 @@ export class PageBuilderService {
742
757
  if (passedConfig && !passedConfig.userSettings) {
743
758
  try {
744
759
  this.pageBuilderStateStore.setIsSaving(true)
745
- this.#saveDomComponentsToLocalStorage()
760
+ this.saveDomComponentsToLocalStorage()
746
761
  await delay(400)
747
762
  } catch (err) {
748
763
  console.error('Error trying saving.', err)
@@ -752,7 +767,7 @@ export class PageBuilderService {
752
767
  }
753
768
  }
754
769
 
755
- handleManualSave = async () => {
770
+ public handleManualSave = async () => {
756
771
  this.startEditing()
757
772
  const passedConfig = this.pageBuilderStateStore.getPageBuilderConfig
758
773
 
@@ -768,7 +783,7 @@ export class PageBuilderService {
768
783
  passedConfig.userSettings.autoSave)
769
784
  ) {
770
785
  this.pageBuilderStateStore.setIsSaving(true)
771
- this.#saveDomComponentsToLocalStorage()
786
+ this.saveDomComponentsToLocalStorage()
772
787
  await delay(400)
773
788
 
774
789
  this.pageBuilderStateStore.setIsSaving(false)
@@ -776,19 +791,19 @@ export class PageBuilderService {
776
791
  }
777
792
  if (passedConfig && !passedConfig.userSettings) {
778
793
  this.pageBuilderStateStore.setIsSaving(true)
779
- this.#saveDomComponentsToLocalStorage()
794
+ this.saveDomComponentsToLocalStorage()
780
795
  await delay(400)
781
796
 
782
797
  this.pageBuilderStateStore.setIsSaving(false)
783
798
  }
784
799
  }
785
800
 
786
- cloneCompObjForDOMInsertion(componentObject: ComponentObject): ComponentObject {
801
+ public cloneCompObjForDOMInsertion(componentObject: ComponentObject): ComponentObject {
787
802
  // Deep clone clone component
788
803
  const clonedComponent = { ...componentObject }
789
804
 
790
- const pageBuilder = document.querySelector('#contains-pagebuilder')
791
- // scoll to top or bottom # end
805
+ const pageBuilder = document.querySelector('#pagebuilder')
806
+ // scoll to top or bottom
792
807
  if (pageBuilder) {
793
808
  // push to top
794
809
  if (this.getComponentArrayAddMethod.value === 'unshift') {
@@ -809,7 +824,7 @@ export class PageBuilderService {
809
824
  const elements = doc.querySelectorAll('*')
810
825
 
811
826
  elements.forEach((element) => {
812
- this.#applyHelperCSSToElements(element as HTMLElement)
827
+ this.applyHelperCSSToElements(element as HTMLElement)
813
828
  })
814
829
 
815
830
  // Add the component id to the section element
@@ -819,7 +834,7 @@ export class PageBuilderService {
819
834
  section.querySelectorAll('[class]').forEach((el) => {
820
835
  el.setAttribute(
821
836
  'class',
822
- this.#addTailwindPrefixToClasses(el.getAttribute('class') || '', 'pbx-'),
837
+ this.addTailwindPrefixToClasses(el.getAttribute('class') || '', 'pbx-'),
823
838
  )
824
839
  })
825
840
 
@@ -843,7 +858,7 @@ export class PageBuilderService {
843
858
  return clonedComponent
844
859
  }
845
860
 
846
- async #removeHoveredAndSelected() {
861
+ private async removeHoveredAndSelected() {
847
862
  const pagebuilder = document.querySelector('#pagebuilder')
848
863
  if (!pagebuilder) return
849
864
 
@@ -859,7 +874,7 @@ export class PageBuilderService {
859
874
  }
860
875
  }
861
876
 
862
- async #syncCurrentClasses() {
877
+ private async syncCurrentClasses() {
863
878
  // convert classList to array
864
879
  const classListArray = Array.from(this.getElement.value?.classList || [])
865
880
 
@@ -867,7 +882,17 @@ export class PageBuilderService {
867
882
  this.pageBuilderStateStore.setCurrentClasses(classListArray)
868
883
  }
869
884
 
870
- handleAddClasses(userSelectedClass: string): void {
885
+ private async syncCurrentStyles() {
886
+ const style = this.getElement.value?.getAttribute('style')
887
+ if (style) {
888
+ const stylesObject = this.parseStyleString(style)
889
+ this.pageBuilderStateStore.setCurrentStyles(stylesObject)
890
+ } else {
891
+ this.pageBuilderStateStore.setCurrentStyles({})
892
+ }
893
+ }
894
+
895
+ public handleAddClasses(userSelectedClass: string): void {
871
896
  if (
872
897
  typeof userSelectedClass === 'string' &&
873
898
  userSelectedClass.trim() !== '' &&
@@ -886,66 +911,84 @@ export class PageBuilderService {
886
911
  this.pageBuilderStateStore.setClass(prefixedClass)
887
912
  }
888
913
  }
889
- handleFontFamily(userSelectedFontFamily?: string): void {
890
- this.#applyElementClassChanges(
914
+
915
+ public handleAddStyle(property: string, value: string): void {
916
+ const element = this.getElement.value
917
+ if (!element || !property || !value) return
918
+
919
+ element.style.setProperty(property, value)
920
+ this.pageBuilderStateStore.setElement(element)
921
+ }
922
+
923
+ public handleRemoveStyle(property: string): void {
924
+ console.log('come her:', property)
925
+ const element = this.getElement.value
926
+ if (!element || !property) return
927
+
928
+ element.style.removeProperty(property)
929
+ this.pageBuilderStateStore.setElement(element)
930
+ }
931
+
932
+ public handleFontFamily(userSelectedFontFamily?: string): void {
933
+ this.applyElementClassChanges(
891
934
  userSelectedFontFamily,
892
935
  tailwindFontStyles.fontFamily,
893
936
  'setFontFamily',
894
937
  )
895
938
  }
896
- handleFontStyle(userSelectedFontStyle?: string): void {
897
- this.#applyElementClassChanges(
939
+ public handleFontStyle(userSelectedFontStyle?: string): void {
940
+ this.applyElementClassChanges(
898
941
  userSelectedFontStyle,
899
942
  tailwindFontStyles.fontStyle,
900
943
  'setFontStyle',
901
944
  )
902
945
  }
903
- handleVerticalPadding(userSelectedVerticalPadding?: string): void {
904
- this.#applyElementClassChanges(
946
+ public handleVerticalPadding(userSelectedVerticalPadding?: string): void {
947
+ this.applyElementClassChanges(
905
948
  userSelectedVerticalPadding,
906
949
  tailwindPaddingAndMargin.verticalPadding,
907
950
  'setFontVerticalPadding',
908
951
  )
909
952
  }
910
- handleHorizontalPadding(userSelectedHorizontalPadding?: string): void {
911
- this.#applyElementClassChanges(
953
+ public handleHorizontalPadding(userSelectedHorizontalPadding?: string): void {
954
+ this.applyElementClassChanges(
912
955
  userSelectedHorizontalPadding,
913
956
  tailwindPaddingAndMargin.horizontalPadding,
914
957
  'setFontHorizontalPadding',
915
958
  )
916
959
  }
917
960
 
918
- handleVerticalMargin(userSelectedVerticalMargin?: string): void {
919
- this.#applyElementClassChanges(
961
+ public handleVerticalMargin(userSelectedVerticalMargin?: string): void {
962
+ this.applyElementClassChanges(
920
963
  userSelectedVerticalMargin,
921
964
  tailwindPaddingAndMargin.verticalMargin,
922
965
  'setFontVerticalMargin',
923
966
  )
924
967
  }
925
- handleHorizontalMargin(userSelectedHorizontalMargin?: string): void {
926
- this.#applyElementClassChanges(
968
+ public handleHorizontalMargin(userSelectedHorizontalMargin?: string): void {
969
+ this.applyElementClassChanges(
927
970
  userSelectedHorizontalMargin,
928
971
  tailwindPaddingAndMargin.horizontalMargin,
929
972
  'setFontHorizontalMargin',
930
973
  )
931
974
  }
932
975
 
933
- handleBorderStyle(borderStyle?: string): void {
934
- this.#applyElementClassChanges(
976
+ public handleBorderStyle(borderStyle?: string): void {
977
+ this.applyElementClassChanges(
935
978
  borderStyle,
936
979
  tailwindBorderStyleWidthPlusColor.borderStyle,
937
980
  'setBorderStyle',
938
981
  )
939
982
  }
940
- handleBorderWidth(borderWidth?: string): void {
941
- this.#applyElementClassChanges(
983
+ public handleBorderWidth(borderWidth?: string): void {
984
+ this.applyElementClassChanges(
942
985
  borderWidth,
943
986
  tailwindBorderStyleWidthPlusColor.borderWidth,
944
987
  'setBorderWidth',
945
988
  )
946
989
  }
947
- handleBorderColor(borderColor?: string): void {
948
- this.#applyElementClassChanges(
990
+ public handleBorderColor(borderColor?: string): void {
991
+ this.applyElementClassChanges(
949
992
  borderColor,
950
993
  tailwindBorderStyleWidthPlusColor.borderColor,
951
994
  'setBorderColor',
@@ -953,48 +996,48 @@ export class PageBuilderService {
953
996
  }
954
997
  // border color, style & width / end
955
998
 
956
- handleBackgroundColor(color?: string): void {
957
- this.#applyElementClassChanges(
999
+ public handleBackgroundColor(color?: string): void {
1000
+ this.applyElementClassChanges(
958
1001
  color,
959
1002
  tailwindColors.backgroundColorVariables,
960
1003
  'setBackgroundColor',
961
1004
  )
962
1005
  }
963
1006
 
964
- handleTextColor(color?: string): void {
965
- this.#applyElementClassChanges(color, tailwindColors.textColorVariables, 'setTextColor')
1007
+ public handleTextColor(color?: string): void {
1008
+ this.applyElementClassChanges(color, tailwindColors.textColorVariables, 'setTextColor')
966
1009
  }
967
1010
 
968
1011
  handleBorderRadiusGlobal(borderRadiusGlobal?: string): void {
969
- this.#applyElementClassChanges(
1012
+ this.applyElementClassChanges(
970
1013
  borderRadiusGlobal,
971
1014
  tailwindBorderRadius.roundedGlobal,
972
1015
  'setBorderRadiusGlobal',
973
1016
  )
974
1017
  }
975
1018
  handleBorderRadiusTopLeft(borderRadiusTopLeft?: string): void {
976
- this.#applyElementClassChanges(
1019
+ this.applyElementClassChanges(
977
1020
  borderRadiusTopLeft,
978
1021
  tailwindBorderRadius.roundedTopLeft,
979
1022
  'setBorderRadiusTopLeft',
980
1023
  )
981
1024
  }
982
1025
  handleBorderRadiusTopRight(borderRadiusTopRight?: string): void {
983
- this.#applyElementClassChanges(
1026
+ this.applyElementClassChanges(
984
1027
  borderRadiusTopRight,
985
1028
  tailwindBorderRadius.roundedTopRight,
986
1029
  'setBorderRadiusTopRight',
987
1030
  )
988
1031
  }
989
1032
  handleBorderRadiusBottomleft(borderRadiusBottomleft?: string): void {
990
- this.#applyElementClassChanges(
1033
+ this.applyElementClassChanges(
991
1034
  borderRadiusBottomleft,
992
1035
  tailwindBorderRadius.roundedBottomLeft,
993
1036
  'setBorderRadiusBottomleft',
994
1037
  )
995
1038
  }
996
1039
  handleBorderRadiusBottomRight(borderRadiusBottomRight?: string): void {
997
- this.#applyElementClassChanges(
1040
+ this.applyElementClassChanges(
998
1041
  borderRadiusBottomRight,
999
1042
  tailwindBorderRadius.roundedBottomRight,
1000
1043
  'setBorderRadiusBottomRight',
@@ -1003,14 +1046,14 @@ export class PageBuilderService {
1003
1046
  // border radius / end
1004
1047
 
1005
1048
  handleFontSizeTablet(userSelectedFontSize?: string): void {
1006
- this.#applyElementClassChanges(
1049
+ this.applyElementClassChanges(
1007
1050
  userSelectedFontSize,
1008
1051
  tailwindFontSizes.fontTablet,
1009
1052
  'setFontTablet',
1010
1053
  )
1011
1054
  }
1012
1055
  handleFontSizeMobile(userSelectedFontSize?: string): void {
1013
- this.#applyElementClassChanges(
1056
+ this.applyElementClassChanges(
1014
1057
  userSelectedFontSize,
1015
1058
  tailwindFontSizes.fontMobile,
1016
1059
  'setFontMobile',
@@ -1018,14 +1061,14 @@ export class PageBuilderService {
1018
1061
  }
1019
1062
 
1020
1063
  handleBackgroundOpacity(opacity?: string): void {
1021
- this.#applyElementClassChanges(
1064
+ this.applyElementClassChanges(
1022
1065
  opacity,
1023
1066
  tailwindOpacities.backgroundOpacities,
1024
1067
  'setBackgroundOpacity',
1025
1068
  )
1026
1069
  }
1027
1070
  handleOpacity(opacity?: string): void {
1028
- this.#applyElementClassChanges(opacity, tailwindOpacities.opacities, 'setOpacity')
1071
+ this.applyElementClassChanges(opacity, tailwindOpacities.opacities, 'setOpacity')
1029
1072
  }
1030
1073
 
1031
1074
  /**
@@ -1038,7 +1081,7 @@ export class PageBuilderService {
1038
1081
  *
1039
1082
  */
1040
1083
 
1041
- deleteAllComponentsFromDOM() {
1084
+ private deleteAllComponentsFromDOM() {
1042
1085
  // Clear the store
1043
1086
  this.pageBuilderStateStore.setComponents([])
1044
1087
 
@@ -1052,8 +1095,8 @@ export class PageBuilderService {
1052
1095
  }
1053
1096
  }
1054
1097
 
1055
- async deleteComponentFromDOM() {
1056
- this.#syncDomToStoreOnly()
1098
+ public async deleteComponentFromDOM() {
1099
+ this.syncDomToStoreOnly()
1057
1100
  await nextTick()
1058
1101
 
1059
1102
  const components = this.getComponents.value
@@ -1089,7 +1132,7 @@ export class PageBuilderService {
1089
1132
 
1090
1133
  // Wait for Vue to finish DOM updates before attaching event listeners.
1091
1134
  await nextTick()
1092
- await this.#addListenersToEditableElements()
1135
+ await this.addListenersToEditableElements()
1093
1136
 
1094
1137
  this.pageBuilderStateStore.setComponent(null)
1095
1138
  this.pageBuilderStateStore.setElement(null)
@@ -1098,7 +1141,7 @@ export class PageBuilderService {
1098
1141
  await this.handleAutoSave()
1099
1142
  }
1100
1143
 
1101
- async deleteElementFromDOM() {
1144
+ public async deleteElementFromDOM() {
1102
1145
  const element = this.getElement.value
1103
1146
  if (!element) return
1104
1147
 
@@ -1129,10 +1172,10 @@ export class PageBuilderService {
1129
1172
  // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
1130
1173
  await nextTick()
1131
1174
  // Attach event listeners to all editable elements in the Builder
1132
- await this.#addListenersToEditableElements()
1175
+ await this.addListenersToEditableElements()
1133
1176
  }
1134
1177
 
1135
- async restoreDeletedElementToDOM() {
1178
+ public async restoreDeletedElementToDOM() {
1136
1179
  // Restore the previously deleted element to the DOM
1137
1180
  const restoredHTML = this.getRestoredElement.value
1138
1181
  const parent = this.getParentElement.value
@@ -1158,10 +1201,10 @@ export class PageBuilderService {
1158
1201
 
1159
1202
  // Wait for Vue to finish DOM updates before attaching event listeners
1160
1203
  await nextTick()
1161
- await this.#addListenersToEditableElements()
1204
+ await this.addListenersToEditableElements()
1162
1205
  }
1163
1206
 
1164
- handleRemoveClasses(userSelectedClass: string): void {
1207
+ public handleRemoveClasses(userSelectedClass: string): void {
1165
1208
  // remove selected class from element
1166
1209
  if (this.getElement.value?.classList.contains(userSelectedClass)) {
1167
1210
  this.getElement.value?.classList.remove(userSelectedClass)
@@ -1173,7 +1216,7 @@ export class PageBuilderService {
1173
1216
 
1174
1217
  // move component
1175
1218
  // runs when html components are rearranged
1176
- reorderComponent(direction: number): void {
1219
+ public reorderComponent(direction: number): void {
1177
1220
  if (!this.getComponents.value || !this.getComponent.value) return
1178
1221
 
1179
1222
  if (this.getComponents.value.length <= 1) return
@@ -1203,7 +1246,7 @@ export class PageBuilderService {
1203
1246
  this.getComponents.value.splice(newIndex, 0, componentToMove)
1204
1247
  }
1205
1248
 
1206
- ensureTextAreaHasContent = () => {
1249
+ public ensureTextAreaHasContent = () => {
1207
1250
  if (!this.getElement.value) return
1208
1251
 
1209
1252
  // text content
@@ -1227,7 +1270,7 @@ export class PageBuilderService {
1227
1270
  }
1228
1271
  }
1229
1272
 
1230
- handleTextInput = async (textContentVueModel: string): Promise<void> => {
1273
+ public handleTextInput = async (textContentVueModel: string): Promise<void> => {
1231
1274
  if (typeof this.getElement.value?.innerHTML !== 'string') {
1232
1275
  return
1233
1276
  }
@@ -1248,7 +1291,7 @@ export class PageBuilderService {
1248
1291
 
1249
1292
  //
1250
1293
  //
1251
- ElOrFirstChildIsIframe() {
1294
+ public ElOrFirstChildIsIframe() {
1252
1295
  if (
1253
1296
  this.getElement.value?.tagName === 'IFRAME' ||
1254
1297
  this.getElement.value?.firstElementChild?.tagName === 'IFRAME'
@@ -1261,7 +1304,7 @@ export class PageBuilderService {
1261
1304
  //
1262
1305
  //
1263
1306
  //
1264
- isSelectedElementValidText() {
1307
+ public isSelectedElementValidText() {
1265
1308
  let reachedElseStatement = false
1266
1309
 
1267
1310
  // Get all child elements of the parentDiv
@@ -1287,7 +1330,7 @@ export class PageBuilderService {
1287
1330
  return reachedElseStatement
1288
1331
  }
1289
1332
 
1290
- previewCurrentDesign() {
1333
+ public previewCurrentDesign() {
1291
1334
  this.pageBuilderStateStore.setElement(null)
1292
1335
 
1293
1336
  const pagebuilder = document.querySelector('#pagebuilder')
@@ -1324,7 +1367,7 @@ export class PageBuilderService {
1324
1367
  * removed from itself and all descendants. Does NOT mutate the live DOM.
1325
1368
  * @param element The HTMLElement to clone and sanitize
1326
1369
  */
1327
- #cloneAndRemoveSelectionAttributes(element: HTMLElement): HTMLElement {
1370
+ private cloneAndRemoveSelectionAttributes(element: HTMLElement): HTMLElement {
1328
1371
  // Deep clone the element
1329
1372
  const clone = element.cloneNode(true) as HTMLElement
1330
1373
 
@@ -1342,14 +1385,14 @@ export class PageBuilderService {
1342
1385
  * Syncs the current DOM state into the in-memory store (getComponents),
1343
1386
  * but does NOT save to localStorage.
1344
1387
  */
1345
- #syncDomToStoreOnly() {
1388
+ private syncDomToStoreOnly() {
1346
1389
  const pagebuilder = document.querySelector('#pagebuilder')
1347
1390
  if (!pagebuilder) return
1348
1391
 
1349
1392
  const componentsToSave: { html_code: string; id: string | null; title: string }[] = []
1350
1393
 
1351
1394
  pagebuilder.querySelectorAll('section[data-componentid]').forEach((section) => {
1352
- const sanitizedSection = this.#cloneAndRemoveSelectionAttributes(section as HTMLElement)
1395
+ const sanitizedSection = this.cloneAndRemoveSelectionAttributes(section as HTMLElement)
1353
1396
  componentsToSave.push({
1354
1397
  html_code: sanitizedSection.outerHTML,
1355
1398
  id: sanitizedSection.getAttribute('data-componentid'),
@@ -1363,8 +1406,8 @@ export class PageBuilderService {
1363
1406
  /**
1364
1407
  * Saves the current DOM state (components) to localStorage.
1365
1408
  */
1366
- #saveDomComponentsToLocalStorage() {
1367
- this.localStorageManager.updateLocalStorageItemName()
1409
+ private saveDomComponentsToLocalStorage() {
1410
+ this.updateLocalStorageItemName()
1368
1411
  const pagebuilder = document.querySelector('#pagebuilder')
1369
1412
  if (!pagebuilder) return
1370
1413
 
@@ -1373,14 +1416,13 @@ export class PageBuilderService {
1373
1416
  hoveredElement.removeAttribute('hovered')
1374
1417
  }
1375
1418
 
1376
- const componentsToSave: { html_code: string; id: string | null; title: string }[] = []
1419
+ const componentsToSave: { html_code: string; title: string }[] = []
1377
1420
 
1378
1421
  pagebuilder.querySelectorAll('section[data-componentid]').forEach((section) => {
1379
- const sanitizedSection = this.#cloneAndRemoveSelectionAttributes(section as HTMLElement)
1422
+ const sanitizedSection = this.cloneAndRemoveSelectionAttributes(section as HTMLElement)
1380
1423
 
1381
1424
  componentsToSave.push({
1382
1425
  html_code: sanitizedSection.outerHTML,
1383
- id: sanitizedSection.getAttribute('data-componentid'),
1384
1426
  title: sanitizedSection.getAttribute('data-component-title') || 'Untitled Component',
1385
1427
  })
1386
1428
  })
@@ -1402,8 +1444,8 @@ export class PageBuilderService {
1402
1444
  localStorage.setItem(keyForSavingFromDomToLocal, JSON.stringify(dataToSave))
1403
1445
  }
1404
1446
  }
1405
- async removeCurrentComponentsFromLocalStorage() {
1406
- this.localStorageManager.updateLocalStorageItemName()
1447
+ private async removeCurrentComponentsFromLocalStorage() {
1448
+ this.updateLocalStorageItemName()
1407
1449
  await nextTick()
1408
1450
 
1409
1451
  const key = this.getLocalStorageItemName.value
@@ -1412,7 +1454,26 @@ export class PageBuilderService {
1412
1454
  }
1413
1455
  }
1414
1456
 
1415
- //
1457
+ public async handleFormSubmission() {
1458
+ await this.removeCurrentComponentsFromLocalStorage()
1459
+ this.deleteAllComponentsFromDOM()
1460
+ }
1461
+
1462
+ private parseStyleString(style: string): Record<string, string> {
1463
+ return style
1464
+ .split(';')
1465
+ .map((s) => s.trim())
1466
+ .filter(Boolean)
1467
+ .reduce(
1468
+ (acc, rule) => {
1469
+ const [key, value] = rule.split(':').map((str) => str.trim())
1470
+ if (key && value) acc[key] = value
1471
+ return acc
1472
+ },
1473
+ {} as Record<string, string>,
1474
+ )
1475
+ }
1476
+
1416
1477
  deleteOldPageBuilderLocalStorage(): void {
1417
1478
  const config = this.pageBuilderStateStore.getPageBuilderConfig
1418
1479
  const formType = config && config.updateOrCreate && config.updateOrCreate.formType
@@ -1466,33 +1527,33 @@ export class PageBuilderService {
1466
1527
  }
1467
1528
 
1468
1529
  // Call this when the user starts editing (e.g., on first change or when resuming a draft)
1469
- startEditing() {
1530
+ public startEditing() {
1470
1531
  this.hasStartedEditing = true
1471
1532
  }
1472
1533
 
1473
1534
  //
1474
- async resumeEditingFromDraft() {
1475
- this.localStorageManager.updateLocalStorageItemName()
1535
+ public async resumeEditingFromDraft() {
1536
+ this.updateLocalStorageItemName()
1476
1537
 
1477
- const localStorageData = this.loadStoredComponentsFromStorage()
1538
+ const localStorageData = this.getSavedPageHtml()
1478
1539
 
1479
1540
  if (localStorageData) {
1480
- this.pageBuilderStateStore.setIsLoadingResumeEditing(true)
1481
1541
  await delay(400)
1482
- await this.#mountComponentsToDOM(localStorageData)
1542
+ this.pageBuilderStateStore.setIsLoadingResumeEditing(true)
1543
+ await this.mountComponentsToDOM(localStorageData)
1483
1544
  this.pageBuilderStateStore.setIsLoadingResumeEditing(false)
1484
1545
  }
1485
1546
 
1486
1547
  // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
1487
1548
  await nextTick()
1488
1549
  // Attach event listeners to all editable elements in the Builder
1489
- await this.#addListenersToEditableElements()
1550
+ await this.addListenersToEditableElements()
1490
1551
  // set loading to false
1491
1552
  this.pageBuilderStateStore.setIsLoadingResumeEditing(false)
1492
1553
  }
1493
1554
 
1494
- async restoreOriginalContent() {
1495
- this.localStorageManager.updateLocalStorageItemName()
1555
+ public async restoreOriginalContent() {
1556
+ this.updateLocalStorageItemName()
1496
1557
 
1497
1558
  this.pageBuilderStateStore.setIsRestoring(true)
1498
1559
  await delay(400)
@@ -1501,56 +1562,52 @@ export class PageBuilderService {
1501
1562
  if (Array.isArray(this.originalComponents)) {
1502
1563
  await this.clearClassesFromPage()
1503
1564
  await this.clearInlineStylesFromPagee()
1504
- await this.#mountComponentsToDOM(JSON.stringify(this.originalComponents), true)
1565
+ await this.mountComponentsToDOM(JSON.stringify(this.originalComponents), true)
1505
1566
  this.removeCurrentComponentsFromLocalStorage()
1506
1567
  }
1507
1568
 
1508
1569
  // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
1509
1570
  await nextTick()
1510
1571
  // Attach event listeners to all editable elements in the Builder
1511
- await this.#addListenersToEditableElements()
1572
+ await this.addListenersToEditableElements()
1512
1573
 
1513
1574
  this.pageBuilderStateStore.setIsRestoring(false)
1514
1575
  }
1515
1576
 
1516
- getStorageItemNameForResource(): string | null {
1577
+ public getStorageItemNameForResource(): string | null {
1517
1578
  return this.getLocalStorageItemName.value
1518
1579
  }
1519
1580
 
1520
- loadStoredComponentsFromStorage() {
1521
- this.localStorageManager.updateLocalStorageItemName()
1581
+ public getSavedPageHtml() {
1522
1582
  if (!this.getLocalStorageItemName.value) return false
1523
1583
 
1524
- if (
1525
- this.getLocalStorageItemName.value &&
1526
- localStorage.getItem(this.getLocalStorageItemName.value)
1527
- ) {
1528
- const savedCurrentDesign = localStorage.getItem(this.getLocalStorageItemName.value)
1584
+ const key = this.getLocalStorageItemName.value
1585
+ if (!key) return false
1529
1586
 
1530
- if (savedCurrentDesign) {
1531
- return savedCurrentDesign
1532
- }
1533
- }
1587
+ const raw = localStorage.getItem(key)
1588
+ if (!raw) return false
1534
1589
 
1535
- return false
1536
- }
1590
+ const parsed = JSON.parse(raw)
1537
1591
 
1538
- /**
1539
- * Sets the image selected from the media library as the "pending" image
1540
- * to be applied to the currently selected element in the builder.
1541
- * This does not update the DOM immediately—call `applyPendingImageToSelectedElement` to commit.
1542
- * @param image - The image object to be staged for application
1543
- */
1544
- stageImageForSelectedElement(image: ImageObject) {
1545
- this.pageBuilderStateStore.setApplyImageToSelection(image)
1592
+ // Object with components and pageSettings
1593
+ if (parsed && Array.isArray(parsed.components)) {
1594
+ const classes = (parsed.pageSettings && parsed.pageSettings.classes) || ''
1595
+ const style = (parsed.pageSettings && parsed.pageSettings.style) || ''
1596
+
1597
+ const sectionsHtml = parsed.components.map((c: ComponentObject) => c.html_code).join('\n')
1598
+ return `<div id="pagebuilder" class="${classes}" style="${style}">\n${sectionsHtml}\n</div>`
1599
+ }
1600
+ return false
1546
1601
  }
1547
1602
 
1548
1603
  /**
1549
- * Applies the staged image (set by `stageImageForSelectedElement`) to the currently selected element.
1604
+ * Applies the staged image to the currently selected element.
1550
1605
  * This updates the builder state and triggers an auto-save.
1551
1606
  * If no element is selected or no image is staged, nothing happens.
1552
1607
  */
1553
- async applyPendingImageToSelectedElement(): Promise<void> {
1608
+ public async applySelectedImage(image: ImageObject): Promise<void> {
1609
+ this.pageBuilderStateStore.setApplyImageToSelection(image)
1610
+
1554
1611
  if (!this.getElement.value) return
1555
1612
 
1556
1613
  // Only apply if an image is staged
@@ -1567,7 +1624,7 @@ export class PageBuilderService {
1567
1624
  * sets that image's src as the base primary image in the builder state.
1568
1625
  * If the element does not meet these criteria, clears the base primary image.
1569
1626
  */
1570
- setBasePrimaryImageFromSelectedElement() {
1627
+ private setBasePrimaryImageFromSelectedElement() {
1571
1628
  if (!this.getElement.value) return
1572
1629
 
1573
1630
  const currentImageContainer = document.createElement('div')
@@ -1587,7 +1644,7 @@ export class PageBuilderService {
1587
1644
  this.pageBuilderStateStore.setBasePrimaryImage(null)
1588
1645
  }
1589
1646
 
1590
- #addHyperlinkToElement(
1647
+ private addHyperlinkToElement(
1591
1648
  hyperlinkEnable: boolean,
1592
1649
  urlInput: string | null,
1593
1650
  openHyperlinkInNewTab: boolean,
@@ -1683,7 +1740,7 @@ export class PageBuilderService {
1683
1740
  }
1684
1741
  }
1685
1742
 
1686
- #checkForHyperlink() {
1743
+ private checkForHyperlink() {
1687
1744
  if (!this.getElement.value) return
1688
1745
 
1689
1746
  const hyperlink = this.getElement.value.querySelector('a')
@@ -1711,7 +1768,7 @@ export class PageBuilderService {
1711
1768
  this.pageBuilderStateStore.setHyberlinkEnable(false)
1712
1769
  }
1713
1770
 
1714
- handleHyperlink(
1771
+ public handleHyperlink(
1715
1772
  hyperlinkEnable?: boolean,
1716
1773
  urlInput?: string | null,
1717
1774
  openHyperlinkInNewTab?: boolean,
@@ -1749,15 +1806,15 @@ export class PageBuilderService {
1749
1806
  }
1750
1807
 
1751
1808
  if (hyperlinkEnable === undefined) {
1752
- this.#checkForHyperlink()
1809
+ this.checkForHyperlink()
1753
1810
  return
1754
1811
  }
1755
1812
 
1756
- this.#addHyperlinkToElement(hyperlinkEnable, urlInput || null, openHyperlinkInNewTab || false)
1813
+ this.addHyperlinkToElement(hyperlinkEnable, urlInput || null, openHyperlinkInNewTab || false)
1757
1814
  }
1758
1815
 
1759
1816
  // Helper method for custom components to easily add components
1760
- async addComponent(componentObject: ComponentObject): Promise<void> {
1817
+ public async addComponent(componentObject: ComponentObject): Promise<void> {
1761
1818
  try {
1762
1819
  const clonedComponent = this.cloneCompObjForDOMInsertion({
1763
1820
  html_code: componentObject.html_code,
@@ -1772,8 +1829,8 @@ export class PageBuilderService {
1772
1829
  : 'push',
1773
1830
  })
1774
1831
 
1775
- const pageBuilder = document.querySelector('#contains-pagebuilder')
1776
- // scoll to top or bottom # end
1832
+ const pageBuilder = document.querySelector('#pagebuilder')
1833
+ // scoll to top or bottom
1777
1834
  if (pageBuilder) {
1778
1835
  // push to bottom
1779
1836
  if (this.getComponentArrayAddMethod.value === 'push') {
@@ -1787,7 +1844,7 @@ export class PageBuilderService {
1787
1844
  // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
1788
1845
  await nextTick()
1789
1846
  // Attach event listeners to all editable elements in the Builder
1790
- await this.#addListenersToEditableElements()
1847
+ await this.addListenersToEditableElements()
1791
1848
 
1792
1849
  await this.handleAutoSave()
1793
1850
  } catch (error) {
@@ -1800,7 +1857,7 @@ export class PageBuilderService {
1800
1857
  * process each element’s class attribute and update the classes accordingly.
1801
1858
  */
1802
1859
 
1803
- #addTailwindPrefixToClasses(classList: string, prefix = 'pbx-'): string {
1860
+ private addTailwindPrefixToClasses(classList: string, prefix = 'pbx-'): string {
1804
1861
  return classList
1805
1862
  .split(/\s+/)
1806
1863
  .map((cls) => {
@@ -1814,7 +1871,7 @@ export class PageBuilderService {
1814
1871
  .join(' ')
1815
1872
  }
1816
1873
 
1817
- #convertStyleObjectToString(
1874
+ private convertStyleObjectToString(
1818
1875
  styleObj: string | Record<string, string> | null | undefined,
1819
1876
  ): string {
1820
1877
  if (!styleObj) return ''
@@ -1828,6 +1885,114 @@ export class PageBuilderService {
1828
1885
  .join(' ')
1829
1886
  }
1830
1887
 
1888
+ /**
1889
+ * Parses a string of HTML and extracts builder components and global page settings.
1890
+ *
1891
+ * ⚠️ **Important:**
1892
+ * - This method expects an **HTML string** containing one or more `<section>...</section>` elements (such as the output from `getSavedPageHtml()` or a previously saved builder HTML string).
1893
+ * - **Do NOT pass a JSON string** (such as the result of `JSON.stringify(componentsArray)`) to this method. Passing a JSON string to `DOMParser.parseFromString(..., 'text/html')` will not produce valid DOM nodes. Instead, it will treat the JSON as plain text, resulting in a `<html><head></head><body>{...json...}</body></html>` structure, not real HTML elements.
1894
+ * - If you pass a JSON string, you will see lots of `\n` and strange HTML, because the parser is just wrapping your JSON in a `<body>` tag as text.
1895
+ *
1896
+ * Why only HTML?
1897
+ * - It enforces a single source of truth for builder state (HTML).
1898
+ * - It prevents misuse (e.g., passing JSON to a DOM parser, which is always a bug).
1899
+ * - It makes your documentation and support much simpler.
1900
+ *
1901
+ * @param htmlString - The HTML string to parse (must contain `<section>...</section>` elements, not JSON).
1902
+ * @returns An object with `components` (array of builder components) and `pageSettings` (global styles for the page).
1903
+ */
1904
+ public parsePageBuilderHTML(htmlString: string): {
1905
+ components: ComponentObject[]
1906
+ pageSettings: PageSettings
1907
+ } {
1908
+ const parser = new DOMParser()
1909
+ const doc = parser.parseFromString(htmlString, 'text/html')
1910
+
1911
+ // Prefix all classes in the document
1912
+ doc.querySelectorAll('[class]').forEach((element) => {
1913
+ const currentClasses = element.getAttribute('class') || ''
1914
+ const prefixedClasses = this.addTailwindPrefixToClasses(currentClasses)
1915
+ element.setAttribute('class', prefixedClasses)
1916
+ })
1917
+
1918
+ const pagebuilderDiv = doc.querySelector('#pagebuilder')
1919
+ let pageSettings: PageSettings = {
1920
+ classes: '',
1921
+ style: {},
1922
+ }
1923
+
1924
+ if (pagebuilderDiv) {
1925
+ const rawStyle = pagebuilderDiv.getAttribute('style') || ''
1926
+ pageSettings = {
1927
+ classes: pagebuilderDiv.className || '',
1928
+ style: this.parseStyleString(rawStyle),
1929
+ }
1930
+ }
1931
+
1932
+ // Always assign sectionNodes before use
1933
+ let sectionNodes: NodeListOf<HTMLElement> = doc.querySelectorAll('section')
1934
+ if (pagebuilderDiv) {
1935
+ sectionNodes = pagebuilderDiv.querySelectorAll('section')
1936
+ }
1937
+
1938
+ // Only use top-level (non-nested) sections as components
1939
+ const topLevelSections = Array.from(sectionNodes).filter(
1940
+ (section) =>
1941
+ !section.parentElement || section.parentElement.tagName.toLowerCase() !== 'section',
1942
+ )
1943
+
1944
+ let components: ComponentObject[] = []
1945
+
1946
+ if (topLevelSections.length > 0) {
1947
+ components = topLevelSections.map((section) => ({
1948
+ id: null,
1949
+ html_code: section.outerHTML.trim(),
1950
+ title:
1951
+ section.getAttribute('data-component-title') ||
1952
+ section.getAttribute('title') ||
1953
+ 'Untitled Component',
1954
+ }))
1955
+ }
1956
+ if (topLevelSections.length === 0) {
1957
+ // No <section> found: treat each first-level child as a component, wrapped in a section
1958
+ const parent = pagebuilderDiv || doc.body
1959
+ const children = Array.from(parent.children)
1960
+ if (children.length > 0) {
1961
+ components = children.map((child) => {
1962
+ // Wrap in a section with data-componentid and data-component-title
1963
+ const section = doc.createElement('section')
1964
+ section.setAttribute('data-component-title', 'Untitled Component')
1965
+ // Optionally: generate a uuid for data-componentid if needed
1966
+ // section.setAttribute('data-componentid', uuidv4())
1967
+ section.innerHTML = child.outerHTML.trim()
1968
+ return {
1969
+ id: null,
1970
+ html_code: section.outerHTML.trim(),
1971
+ title: 'Untitled Component',
1972
+ }
1973
+ })
1974
+ }
1975
+ if (children.length === 0) {
1976
+ // No children: wrap the entire content in a <section> as a single component
1977
+ const section = doc.createElement('section')
1978
+ section.setAttribute('data-component-title', 'Untitled Component')
1979
+ section.innerHTML = parent.innerHTML.trim()
1980
+ components = [
1981
+ {
1982
+ id: null,
1983
+ html_code: section.outerHTML.trim(),
1984
+ title: 'Untitled Component',
1985
+ },
1986
+ ]
1987
+ }
1988
+ }
1989
+
1990
+ return {
1991
+ components,
1992
+ pageSettings,
1993
+ }
1994
+ }
1995
+
1831
1996
  /**
1832
1997
  * Parse and set components from JSON or HTML data
1833
1998
  *
@@ -1840,56 +2005,74 @@ export class PageBuilderService {
1840
2005
  * @param data - JSON string (e.g., '[{"html_code":"...","id":"123","title":"..."}]')
1841
2006
  * OR HTML string (e.g., '<section data-componentid="123">...</section>')
1842
2007
  */
1843
- async #mountComponentsToDOM(htmlString: string, usePassedPageSettings?: boolean): Promise<void> {
1844
- // Auto-detect if input is JSON or HTML
2008
+ private async mountComponentsToDOM(
2009
+ htmlString: string,
2010
+ usePassedPageSettings?: boolean,
2011
+ ): Promise<void> {
2012
+ /**
2013
+ * Mounts builder components to the DOM from either JSON or HTML input.
2014
+ *
2015
+ * Input format detection:
2016
+ * - If the input starts with `[` or `{`, it is treated as JSON (array or object).
2017
+ * - If the input starts with `<`, it is treated as HTML.
2018
+ *
2019
+ * When to use which format:
2020
+ *
2021
+ * 1. JSON input (from localStorage, API, or internal state like pina):
2022
+ * - Use when restoring builder state from localStorage, an API, or a previously saved draft.
2023
+ * - Example: `localStorage.getItem(...)` or API returns a JSON stringified array/object of components.
2024
+ * - This is the most common format for drafts, autosave, and programmatic state management.
2025
+ * - Example usage:
2026
+ * await this.mountComponentsToDOM(JSON.stringify(getComponents))
2027
+ *
2028
+ * 2. HTML input (from HTML snapshot, import, or published output):
2029
+ * - Use when restoring from a published HTML snapshot, importing a static HTML export, or loading the builder from a previously published HTML string.
2030
+ * - Example: output from `getSavedPageHtml()` or a static HTML export.
2031
+ * - This is used for restoring the builder from a published state, importing, or previewing published content.
2032
+ * - Example usage:
2033
+ * await this.mountComponentsToDOM(savedHtmlString)
2034
+ *
2035
+ * Best practice:
2036
+ * - Use JSON for local storage drafts, autosave, and API-driven workflows.
2037
+ * - Use HTML for published/imported content from DB or when restoring from a static HTML snapshot.
2038
+ *
2039
+ * The method auto-detects the format and calls the appropriate parser.
2040
+ */
1845
2041
  const trimmedData = htmlString.trim()
1846
2042
 
1847
2043
  if (trimmedData.startsWith('[') || trimmedData.startsWith('{')) {
1848
- // Looks like JSON - parse as JSON
1849
- await this.#parseJSONComponents(trimmedData, usePassedPageSettings)
2044
+ // JSON input: Use this when restoring from localStorage, API, or internal builder state (drafts, autosave, etc.)
2045
+ await this.parseJSONComponents(trimmedData, usePassedPageSettings)
1850
2046
  return
1851
2047
  }
1852
2048
  if (trimmedData.startsWith('<')) {
1853
- // Looks like HTML - parse as HTML
1854
- await this.#parseHTMLComponents(trimmedData, usePassedPageSettings)
2049
+ // HTML input: Use this when restoring from a published HTML snapshot, import, or static HTML export
2050
+ await this.parseHTMLComponents(trimmedData, usePassedPageSettings)
1855
2051
  return
1856
2052
  }
1857
2053
 
1858
- await this.#parseJSONComponents(trimmedData, usePassedPageSettings)
2054
+ // Fallback: If format is unknown, default to JSON parser (defensive)
2055
+ await this.parseJSONComponents(trimmedData, usePassedPageSettings)
1859
2056
  }
1860
2057
 
1861
2058
  // Private method to parse JSON components and save pageBuilderContentSavedAt to localStorage
1862
- async #parseJSONComponents(jsonData: string, usePassedPageSettings?: boolean): Promise<void> {
1863
- const storedPageSettings =
2059
+ private async parseJSONComponents(
2060
+ jsonData: string,
2061
+ usePassedPageSettings?: boolean,
2062
+ ): Promise<void> {
2063
+ const pageSettings =
1864
2064
  this.pageBuilderStateStore.getPageBuilderConfig &&
1865
2065
  this.pageBuilderStateStore.getPageBuilderConfig.pageSettings
1866
2066
 
2067
+ const userPageSettings = usePassedPageSettings ? pageSettings : null
1867
2068
  try {
1868
2069
  const parsedData = JSON.parse(jsonData)
1869
2070
  let componentsArray: ComponentObject[] = []
1870
2071
 
1871
- // Decide which pageSettings to use
1872
- const pageSettings = usePassedPageSettings
1873
- ? storedPageSettings
1874
- : parsedData && parsedData.pageSettings
1875
- ? parsedData.pageSettings
1876
- : null
1877
-
1878
- // Restore page-level settings like class and style
1879
- if (pageSettings) {
1880
- const pagebuilder = document.querySelector('#pagebuilder') as HTMLElement
1881
- if (pagebuilder) {
1882
- pagebuilder.removeAttribute('class')
1883
- pagebuilder.removeAttribute('style')
1884
- pagebuilder.className = pageSettings.classes || ''
1885
- pagebuilder.setAttribute('style', this.#convertStyleObjectToString(pageSettings.style))
1886
- }
1887
- }
1888
-
1889
- // Support both old and new structure
1890
2072
  if (Array.isArray(parsedData)) {
1891
2073
  componentsArray = parsedData
1892
- } else if (parsedData && Array.isArray(parsedData.components)) {
2074
+ }
2075
+ if (parsedData && Array.isArray(parsedData.components)) {
1893
2076
  componentsArray = parsedData.components
1894
2077
  }
1895
2078
 
@@ -1906,7 +2089,7 @@ export class PageBuilderService {
1906
2089
  section.querySelectorAll('[class]').forEach((el) => {
1907
2090
  el.setAttribute(
1908
2091
  'class',
1909
- this.#addTailwindPrefixToClasses(el.getAttribute('class') || '', 'pbx-'),
2092
+ this.addTailwindPrefixToClasses(el.getAttribute('class') || '', 'pbx-'),
1910
2093
  )
1911
2094
  })
1912
2095
 
@@ -1933,14 +2116,28 @@ export class PageBuilderService {
1933
2116
  this.pageBuilderStateStore.setComponents(savedCurrentDesign)
1934
2117
 
1935
2118
  await nextTick()
1936
- await this.#addListenersToEditableElements()
2119
+ await this.addListenersToEditableElements()
2120
+
2121
+ if (userPageSettings && pageSettings) {
2122
+ const pagebuilder = document.querySelector('#pagebuilder') as HTMLElement
2123
+ if (pagebuilder) {
2124
+ pagebuilder.removeAttribute('class')
2125
+ pagebuilder.removeAttribute('style')
2126
+ pagebuilder.className = pageSettings.classes || ''
2127
+ pagebuilder.setAttribute('style', this.convertStyleObjectToString(pageSettings.style))
2128
+ }
2129
+ }
1937
2130
  } catch (error) {
1938
2131
  console.error('Error parsing JSON components:', error)
1939
2132
  this.deleteAllComponentsFromDOM()
1940
2133
  }
1941
2134
  }
2135
+
1942
2136
  // Private method to parse HTML components
1943
- async #parseHTMLComponents(htmlData: string, usePassedPageSettings?: boolean): Promise<void> {
2137
+ private async parseHTMLComponents(
2138
+ htmlData: string,
2139
+ usePassedPageSettings?: boolean,
2140
+ ): Promise<void> {
1944
2141
  try {
1945
2142
  const parser = new DOMParser()
1946
2143
  const doc = parser.parseFromString(htmlData, 'text/html')
@@ -1971,10 +2168,7 @@ export class PageBuilderService {
1971
2168
  livePageBuilder.removeAttribute('class')
1972
2169
  livePageBuilder.removeAttribute('style')
1973
2170
  livePageBuilder.className = pageSettings.classes || ''
1974
- livePageBuilder.setAttribute(
1975
- 'style',
1976
- this.#convertStyleObjectToString(pageSettings.style),
1977
- )
2171
+ livePageBuilder.setAttribute('style', this.convertStyleObjectToString(pageSettings.style))
1978
2172
  }
1979
2173
  }
1980
2174
 
@@ -1987,7 +2181,7 @@ export class PageBuilderService {
1987
2181
  section.querySelectorAll('[class]').forEach((el) => {
1988
2182
  el.setAttribute(
1989
2183
  'class',
1990
- this.#addTailwindPrefixToClasses(el.getAttribute('class') || '', 'pbx-'),
2184
+ this.addTailwindPrefixToClasses(el.getAttribute('class') || '', 'pbx-'),
1991
2185
  )
1992
2186
  })
1993
2187
 
@@ -2019,67 +2213,192 @@ export class PageBuilderService {
2019
2213
  // Clear selections and re-bind events
2020
2214
  await this.clearHtmlSelection()
2021
2215
  await nextTick()
2022
- await this.#addListenersToEditableElements()
2216
+ await this.addListenersToEditableElements()
2023
2217
  } catch (error) {
2024
2218
  console.error('Error parsing HTML components:', error)
2025
2219
  this.deleteAllComponentsFromDOM()
2026
2220
  }
2027
2221
  }
2028
2222
 
2029
- async initializeElementStyles(): Promise<void> {
2223
+ private updateLocalStorageItemName(): void {
2224
+ const formtype =
2225
+ this.pageBuilderStateStore.getPageBuilderConfig &&
2226
+ this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
2227
+ this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType
2228
+
2229
+ const formname =
2230
+ this.pageBuilderStateStore.getPageBuilderConfig &&
2231
+ this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
2232
+ this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formName
2233
+
2234
+ const resourceData =
2235
+ this.pageBuilderStateStore.getPageBuilderConfig &&
2236
+ this.pageBuilderStateStore.getPageBuilderConfig.resourceData
2237
+
2238
+ // Logic for create resource
2239
+ if (formtype === 'create') {
2240
+ if (formname && formname.length > 0) {
2241
+ this.pageBuilderStateStore.setLocalStorageItemName(
2242
+ `page-builder-create-resource-${this.sanitizeForLocalStorage(formname)}`,
2243
+ )
2244
+ return
2245
+ }
2246
+
2247
+ this.pageBuilderStateStore.setLocalStorageItemName(`page-builder-create-resource`)
2248
+ return
2249
+ }
2250
+
2251
+ // Logic for create
2252
+ // Logic for update and with resource form name
2253
+ if (formtype === 'update') {
2254
+ if (typeof formname === 'string' && formname.length > 0) {
2255
+ //
2256
+ //
2257
+ if (resourceData && resourceData != null && !resourceData.title) {
2258
+ // Check if id is missing, null, undefined, or an empty string (after trimming)
2259
+ if (!resourceData.id || typeof resourceData.id === 'string') {
2260
+ this.pageBuilderStateStore.setLocalStorageItemName(
2261
+ `page-builder-update-resource-${this.sanitizeForLocalStorage(formname)}`,
2262
+ )
2263
+ return
2264
+ }
2265
+ }
2266
+
2267
+ // Runs when resourceData has title but no ID
2268
+ if (resourceData && resourceData != null) {
2269
+ if (
2270
+ resourceData.title &&
2271
+ typeof resourceData.title === 'string' &&
2272
+ resourceData.title.length > 0
2273
+ ) {
2274
+ if (!resourceData.id || typeof resourceData.id === 'string') {
2275
+ this.pageBuilderStateStore.setLocalStorageItemName(
2276
+ `page-builder-update-resource-${this.sanitizeForLocalStorage(formname)}-${this.sanitizeForLocalStorage(resourceData.title)}`,
2277
+ )
2278
+ return
2279
+ }
2280
+ }
2281
+ }
2282
+
2283
+ // Runs when resourceData has ID but no title
2284
+ if (resourceData && resourceData != null) {
2285
+ if (!resourceData.title && typeof resourceData.title !== 'string') {
2286
+ if (resourceData.id || typeof resourceData.id === 'number') {
2287
+ this.pageBuilderStateStore.setLocalStorageItemName(
2288
+ `page-builder-update-resource-${this.sanitizeForLocalStorage(formname)}-${this.sanitizeForLocalStorage(String(resourceData.id))}`,
2289
+ )
2290
+ return
2291
+ }
2292
+ }
2293
+ }
2294
+
2295
+ // Runs when resourceData has both title and ID
2296
+ if (resourceData && resourceData != null) {
2297
+ if (
2298
+ resourceData.title &&
2299
+ typeof resourceData.title === 'string' &&
2300
+ resourceData.title.length > 0
2301
+ ) {
2302
+ if (resourceData.id || typeof resourceData.id === 'number') {
2303
+ this.pageBuilderStateStore.setLocalStorageItemName(
2304
+ `page-builder-update-resource-${this.sanitizeForLocalStorage(formname)}-${this.sanitizeForLocalStorage(resourceData.title)}-${this.sanitizeForLocalStorage(String(resourceData.id))}`,
2305
+ )
2306
+ return
2307
+ }
2308
+ }
2309
+ }
2310
+ }
2311
+
2312
+ // Logic for update without without formname
2313
+ if (!formname || (typeof formname === 'string' && formname.length === 0)) {
2314
+ //
2315
+ //
2316
+ if (resourceData && resourceData != null && !resourceData.title) {
2317
+ // Check if id is missing, null, undefined, or an empty string (after trimming)
2318
+ if (!resourceData.id || typeof resourceData.id === 'string') {
2319
+ this.pageBuilderStateStore.setLocalStorageItemName(`page-builder-update-resource`)
2320
+ return
2321
+ }
2322
+ }
2323
+
2324
+ // Runs when resourceData has title but no ID
2325
+ if (resourceData && resourceData != null) {
2326
+ if (
2327
+ resourceData.title &&
2328
+ typeof resourceData.title === 'string' &&
2329
+ resourceData.title.length > 0
2330
+ ) {
2331
+ if (!resourceData.id || typeof resourceData.id === 'string') {
2332
+ this.pageBuilderStateStore.setLocalStorageItemName(
2333
+ `page-builder-update-resource-${this.sanitizeForLocalStorage(resourceData.title)}`,
2334
+ )
2335
+ return
2336
+ }
2337
+ }
2338
+ }
2339
+
2340
+ // Runs when resourceData has ID but no title
2341
+ if (resourceData && resourceData != null) {
2342
+ if (!resourceData.title && typeof resourceData.title !== 'string') {
2343
+ if (resourceData.id || typeof resourceData.id === 'number') {
2344
+ this.pageBuilderStateStore.setLocalStorageItemName(
2345
+ `page-builder-update-resource-${this.sanitizeForLocalStorage(String(resourceData.id))}`,
2346
+ )
2347
+ return
2348
+ }
2349
+ }
2350
+ }
2351
+
2352
+ // Runs when resourceData has both title and ID
2353
+ if (resourceData && resourceData != null) {
2354
+ if (
2355
+ resourceData.title &&
2356
+ typeof resourceData.title === 'string' &&
2357
+ resourceData.title.length > 0
2358
+ ) {
2359
+ if (resourceData.id || typeof resourceData.id === 'number') {
2360
+ this.pageBuilderStateStore.setLocalStorageItemName(
2361
+ `page-builder-update-resource-${this.sanitizeForLocalStorage(resourceData.title)}-${this.sanitizeForLocalStorage(String(resourceData.id))}`,
2362
+ )
2363
+ return
2364
+ }
2365
+ }
2366
+ }
2367
+ }
2368
+ }
2369
+ }
2370
+
2371
+ public async initializeElementStyles(): Promise<void> {
2030
2372
  // Wait for Vue to finish DOM updates before attaching event listeners.
2031
2373
  // This ensure elements exist in the DOM.
2032
2374
  await nextTick()
2033
2375
 
2034
- // handle custom URL
2035
2376
  this.handleHyperlink(undefined, null, false)
2036
- // handle opacity
2037
2377
  this.handleOpacity(undefined)
2038
- // handle BG opacity
2039
2378
  this.handleBackgroundOpacity(undefined)
2040
- // displayed image
2041
2379
  this.setBasePrimaryImageFromSelectedElement()
2042
- // border style
2043
2380
  this.handleBorderStyle(undefined)
2044
- // border width
2045
2381
  this.handleBorderWidth(undefined)
2046
- // border color
2047
2382
  this.handleBorderColor(undefined)
2048
- // border radius
2049
2383
  this.handleBorderRadiusGlobal(undefined)
2050
- // border radius
2051
2384
  this.handleBorderRadiusTopLeft(undefined)
2052
- // border radius
2053
2385
  this.handleBorderRadiusTopRight(undefined)
2054
- // border radius
2055
2386
  this.handleBorderRadiusBottomleft(undefined)
2056
- // border radius
2057
2387
  this.handleBorderRadiusBottomRight(undefined)
2058
- // handle font size
2059
2388
  this.handleFontSizeBase(undefined)
2060
2389
  this.handleFontSizeDesktop(undefined)
2061
2390
  this.handleFontSizeTablet(undefined)
2062
2391
  this.handleFontSizeMobile(undefined)
2063
- // handle font weight
2064
2392
  this.handleFontWeight(undefined)
2065
- // handle font family
2066
-
2067
2393
  this.handleFontFamily(undefined)
2068
- // handle font style
2069
2394
  this.handleFontStyle(undefined)
2070
- // handle vertical padding
2071
2395
  this.handleVerticalPadding(undefined)
2072
- // handle horizontal padding
2073
2396
  this.handleHorizontalPadding(undefined)
2074
- // handle vertical margin
2075
2397
  this.handleVerticalMargin(undefined)
2076
- // handle horizontal margin
2077
2398
  this.handleHorizontalMargin(undefined)
2078
- // handle color
2079
2399
  this.handleBackgroundColor(undefined)
2080
- // handle text color
2081
2400
  this.handleTextColor(undefined)
2082
- // handle classes
2083
- await this.#syncCurrentClasses()
2401
+ await this.syncCurrentClasses()
2402
+ await this.syncCurrentStyles()
2084
2403
  }
2085
2404
  }