@myissue/vue-website-page-builder 3.3.1 → 3.3.12

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.
@@ -1,5 +1,11 @@
1
1
  // Type definitions
2
- import type { ComponentObject, ImageObject, PageBuilderConfig } from '../types'
2
+ import type {
3
+ BuilderResourceData,
4
+ ComponentObject,
5
+ ImageObject,
6
+ PageBuilderConfig,
7
+ StartBuilderResult,
8
+ } from '../types'
3
9
 
4
10
  import type { usePageBuilderStateStore } from '../stores/page-builder-state'
5
11
 
@@ -18,11 +24,7 @@ import { isEmptyObject } from '../helpers/isEmptyObject'
18
24
 
19
25
  export class PageBuilderService {
20
26
  // Class properties with types
21
- private nextTick: Promise<void>
22
- private containsPagebuilder: Element | null
23
- // private pageBuilder: Element | null
24
27
  private pageBuilderStateStore: ReturnType<typeof usePageBuilderStateStore>
25
- private getTextAreaVueModel: ComputedRef<string | null>
26
28
  private getLocalStorageItemName: ComputedRef<string | null>
27
29
  private getApplyImageToSelection: ComputedRef<ImageObject>
28
30
  private getHyberlinkEnable: ComputedRef<boolean>
@@ -42,12 +44,9 @@ export class PageBuilderService {
42
44
  private pendingMountData: string | null = null
43
45
 
44
46
  constructor(pageBuilderStateStore: ReturnType<typeof usePageBuilderStateStore>) {
45
- this.nextTick = nextTick()
46
47
  this.hasStartedEditing = false
47
- this.containsPagebuilder = document.querySelector('#contains-pagebuilder')
48
48
  this.pageBuilderStateStore = pageBuilderStateStore
49
49
 
50
- this.getTextAreaVueModel = computed(() => this.pageBuilderStateStore.getTextAreaVueModel)
51
50
  this.getLocalStorageItemName = computed(
52
51
  () => this.pageBuilderStateStore.getLocalStorageItemName,
53
52
  )
@@ -176,6 +175,38 @@ export class PageBuilderService {
176
175
  }
177
176
  }
178
177
 
178
+ #validateUserProvidedComponents(components: BuilderResourceData) {
179
+ // Must be an array
180
+ if (!Array.isArray(components)) {
181
+ return {
182
+ error: true,
183
+ reason: "'components' must be an array.",
184
+ }
185
+ }
186
+
187
+ // If empty array, that's acceptable
188
+ if (components.length === 0) {
189
+ return { error: false }
190
+ }
191
+
192
+ // Check that the first item looks like a component
193
+ const first = components[0]
194
+
195
+ const isObject = typeof first === 'object' && first !== null
196
+ const hasHtmlCodeKey = 'html_code' in first
197
+
198
+ if (!isObject || !hasHtmlCodeKey) {
199
+ return {
200
+ error: true,
201
+ reason: "Each component must be an object and include an 'html_code' key.",
202
+ }
203
+ }
204
+
205
+ return {
206
+ message: 'Everything looks good. Components structure is valid.',
207
+ }
208
+ }
209
+
179
210
  #validateConfig(config: PageBuilderConfig): void {
180
211
  const defaultConfigValues = {
181
212
  updateOrCreate: {
@@ -204,7 +235,19 @@ export class PageBuilderService {
204
235
  *
205
236
  * @param config - The configuration object for the Page Builder.
206
237
  */
207
- async startBuilder(config: PageBuilderConfig): Promise<void> {
238
+ async startBuilder(
239
+ config: PageBuilderConfig,
240
+ components?: BuilderResourceData,
241
+ ): 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
+
208
251
  // Reactive flag signals to the UI that the builder has been successfully initialized
209
252
  // Prevents builder actions to prevent errors caused by missing DOM .
210
253
  this.pageBuilderStateStore.setBuilderStarted(true)
@@ -223,10 +266,14 @@ export class PageBuilderService {
223
266
  // Update the localStorage key name based on the config/resource
224
267
  this.#updateLocalStorageItemName()
225
268
 
226
- this.completeBuilderInitialization()
269
+ const formType = config.updateOrCreate && config.updateOrCreate.formType
270
+ if (formType === 'create') {
271
+ await this.mountComponentsToDOM('')
272
+ }
227
273
  }
228
274
 
229
- async completeBuilderInitialization() {
275
+ async #completeBuilderInitialization() {
276
+ console.log('complete builder..')
230
277
  const pagebuilder = document.querySelector('#pagebuilder')
231
278
  if (!pagebuilder) return
232
279
 
@@ -432,7 +479,7 @@ export class PageBuilderService {
432
479
  this.pageBuilderStateStore.setIsSaving(true)
433
480
  // Deselect any selected or hovered elements in the builder UI
434
481
  //
435
- await this.saveComponentsLocalStorage()
482
+ this.#saveDomComponentsToLocalStorage()
436
483
  await this.delay(500)
437
484
  } catch (err) {
438
485
  console.error('Error trying auto save.', err)
@@ -444,7 +491,7 @@ export class PageBuilderService {
444
491
  if (passedConfig && !passedConfig.userSettings) {
445
492
  try {
446
493
  this.pageBuilderStateStore.setIsSaving(true)
447
- await this.saveComponentsLocalStorage()
494
+ this.#saveDomComponentsToLocalStorage()
448
495
  await this.delay(300)
449
496
  } catch (err) {
450
497
  console.error('Error trying saving.', err)
@@ -470,7 +517,7 @@ export class PageBuilderService {
470
517
  passedConfig.userSettings.autoSave)
471
518
  ) {
472
519
  this.pageBuilderStateStore.setIsSaving(true)
473
- await this.saveComponentsLocalStorage()
520
+ this.#saveDomComponentsToLocalStorage()
474
521
  await this.delay(300)
475
522
 
476
523
  this.pageBuilderStateStore.setIsSaving(false)
@@ -478,7 +525,7 @@ export class PageBuilderService {
478
525
  }
479
526
  if (passedConfig && !passedConfig.userSettings) {
480
527
  this.pageBuilderStateStore.setIsSaving(true)
481
- await this.saveComponentsLocalStorage()
528
+ this.#saveDomComponentsToLocalStorage()
482
529
  await this.delay(300)
483
530
 
484
531
  this.pageBuilderStateStore.setIsSaving(false)
@@ -489,15 +536,16 @@ export class PageBuilderService {
489
536
  // Deep clone clone component
490
537
  const clonedComponent = { ...componentObject }
491
538
 
539
+ const pageBuilder = document.querySelector('#contains-pagebuilder')
492
540
  // scoll to top or bottom # end
493
- if (this.containsPagebuilder) {
541
+ if (pageBuilder) {
494
542
  if (
495
543
  this.getComponentArrayAddMethod.value === 'unshift' ||
496
544
  this.getComponentArrayAddMethod.value === 'push'
497
545
  ) {
498
546
  // push to top
499
547
  if (this.getComponentArrayAddMethod.value === 'unshift') {
500
- this.containsPagebuilder.scrollTo({
548
+ pageBuilder.scrollTo({
501
549
  top: 0,
502
550
  behavior: 'smooth',
503
551
  })
@@ -505,9 +553,8 @@ export class PageBuilderService {
505
553
 
506
554
  // push to bottom
507
555
  if (this.getComponentArrayAddMethod.value === 'push') {
508
- const maxHeight = this.containsPagebuilder.scrollHeight
509
- this.containsPagebuilder.scrollTo({
510
- top: maxHeight,
556
+ pageBuilder.scrollTo({
557
+ top: 0,
511
558
  behavior: 'smooth',
512
559
  })
513
560
  }
@@ -601,80 +648,6 @@ export class PageBuilderService {
601
648
  }
602
649
  }
603
650
 
604
- handleRemoveClasses(userSelectedClass: string): void {
605
- // remove selected class from element
606
- if (this.getElement.value?.classList.contains(userSelectedClass)) {
607
- this.getElement.value?.classList.remove(userSelectedClass)
608
-
609
- this.pageBuilderStateStore.setElement(this.getElement.value)
610
- this.pageBuilderStateStore.removeClass(userSelectedClass)
611
- }
612
- }
613
-
614
- handleDeleteElement() {
615
- // Get the element to be deleted
616
- const element = this.getElement.value
617
-
618
- if (!element) return
619
-
620
- if (!element?.parentNode) {
621
- this.pageBuilderStateStore.setComponent(null)
622
- this.pageBuilderStateStore.setElement(null)
623
- return
624
- }
625
-
626
- // Store the parent of the deleted element
627
- // if parent element tag is section remove the hole component
628
- if (element.parentElement?.tagName !== 'SECTION') {
629
- this.pageBuilderStateStore.setParentElement(element.parentNode as HTMLElement)
630
-
631
- // Store the outerHTML of the deleted element
632
- this.pageBuilderStateStore.setRestoredElement(element.outerHTML)
633
-
634
- // Store the next sibling of the deleted element
635
- this.pageBuilderStateStore.setNextSibling(element.nextSibling as HTMLElement | null)
636
- }
637
-
638
- // if parent element tag is section remove the hole component
639
- if (element.parentElement?.tagName === 'SECTION') {
640
- this.deleteSelectedComponent()
641
- }
642
-
643
- // Remove the element from the DOM
644
- element.remove()
645
- this.pageBuilderStateStore.setComponent(null)
646
- this.pageBuilderStateStore.setElement(null)
647
- }
648
-
649
- async handleRestoreElement() {
650
- // Get the stored deleted element and its parent
651
- if (this.getRestoredElement.value && this.getParentElement.value) {
652
- // Create a new element from the stored outerHTML
653
- const newElement = document.createElement('div')
654
- // Fixed type conversion issue
655
- newElement.innerHTML = this.getRestoredElement.value
656
-
657
- // Append the restored element to its parent
658
- // Insert the restored element before its next sibling in its parent
659
- if (newElement.firstChild && this.getParentElement.value) {
660
- // insertBefore can accept null as second parameter (will append to end)
661
- this.getParentElement.value.insertBefore(newElement.firstChild, this.getNextSibling.value)
662
- }
663
- }
664
-
665
- // Clear
666
- this.pageBuilderStateStore.setParentElement(null)
667
- this.pageBuilderStateStore.setRestoredElement(null)
668
- this.pageBuilderStateStore.setNextSibling(null)
669
- this.pageBuilderStateStore.setComponent(null)
670
- this.pageBuilderStateStore.setElement(null)
671
-
672
- // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
673
- await nextTick()
674
- // Attach event listeners to all editable elements in the Builder
675
- await this.#addListenersToEditableElements()
676
- }
677
-
678
651
  handleFontWeight(userSelectedFontWeight?: string): void {
679
652
  this.#applyElementClassChanges(
680
653
  userSelectedFontWeight,
@@ -835,15 +808,40 @@ export class PageBuilderService {
835
808
  this.#applyElementClassChanges(opacity, tailwindOpacities.opacities, 'setOpacity')
836
809
  }
837
810
 
838
- deleteAllComponents() {
811
+ /**
812
+ * Removes all components from both the builder state and the DOM.
813
+ *
814
+ * - First clears the components array in the store.
815
+ * - Then, as a defensive measure, also manually removes all sections elements from the DOM.
816
+ *
817
+ * This manual DOM clearing is only optional
818
+ *
819
+ */
820
+
821
+ deleteAllComponentsFromDOM() {
822
+ // Clear the store
839
823
  this.pageBuilderStateStore.setComponents([])
824
+
825
+ // Also clear the DOM
826
+ const pagebuilder = document.querySelector('#pagebuilder')
827
+ if (pagebuilder) {
828
+ // Remove all section elements (assuming each component is a <section>)
829
+ pagebuilder
830
+ .querySelectorAll('section[data-componentid]')
831
+ .forEach((section) => section.remove())
832
+ }
840
833
  }
841
834
 
842
- async deleteSelectedComponent() {
843
- if (!this.getComponents.value || !this.getComponent.value) return
835
+ async deleteComponentFromDOM() {
836
+ this.#syncDomToStoreOnly()
837
+ await nextTick()
838
+
839
+ const components = this.getComponents.value
840
+
841
+ if (!components) return
844
842
 
845
843
  // Find the index of the component to delete
846
- const indexToDelete = this.getComponents.value.findIndex(
844
+ const indexToDelete = components.findIndex(
847
845
  (component) => component.id === this.getComponent.value?.id,
848
846
  )
849
847
 
@@ -852,17 +850,99 @@ export class PageBuilderService {
852
850
  return
853
851
  }
854
852
 
855
- // Remove the component from the array
856
- this.getComponents.value.splice(indexToDelete, 1)
857
- this.pageBuilderStateStore.setComponents(this.getComponents.value)
853
+ // Create a new array without the deleted component (avoid mutating original array)
854
+ const newComponents = [
855
+ ...components.slice(0, indexToDelete),
856
+ ...components.slice(indexToDelete + 1),
857
+ ]
858
858
 
859
- // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
859
+ this.pageBuilderStateStore.setComponents(newComponents)
860
+
861
+ // Remove the section from the DOM as well
862
+ const pagebuilder = document.querySelector('#pagebuilder')
863
+ if (pagebuilder && this.getComponent.value?.id) {
864
+ const section = pagebuilder.querySelector(
865
+ `section[data-componentid="${this.getComponent.value.id}"]`,
866
+ )
867
+ if (section) section.remove()
868
+ }
869
+
870
+ // Wait for Vue to finish DOM updates before attaching event listeners.
860
871
  await nextTick()
861
- // Attach event listeners to all editable elements in the Builder
862
872
  await this.#addListenersToEditableElements()
863
873
 
864
874
  this.pageBuilderStateStore.setComponent(null)
865
875
  this.pageBuilderStateStore.setElement(null)
876
+
877
+ // Optional: auto-save after deletion
878
+ await this.handleAutoSave()
879
+ }
880
+
881
+ async deleteElementFromDOM() {
882
+ const element = this.getElement.value
883
+ if (!element) return
884
+
885
+ if (!element.parentNode) {
886
+ this.pageBuilderStateStore.setComponent(null)
887
+ this.pageBuilderStateStore.setElement(null)
888
+ return
889
+ }
890
+
891
+ // If the element is inside a section, but not the section itself, store info for undo/restore
892
+ if (element.parentElement?.tagName !== 'SECTION') {
893
+ this.pageBuilderStateStore.setParentElement(element.parentNode as HTMLElement)
894
+ this.pageBuilderStateStore.setRestoredElement(element.outerHTML)
895
+ this.pageBuilderStateStore.setNextSibling(element.nextSibling as HTMLElement | null)
896
+ // Remove only the element itself from the DOM
897
+ element.remove()
898
+ } else {
899
+ // If the element's parent is a section, remove the whole component (section)
900
+ await this.deleteComponentFromDOM()
901
+ // No need to call element.remove() here, as the section is already removed
902
+ }
903
+
904
+ // Clear selection state
905
+ this.pageBuilderStateStore.setComponent(null)
906
+ this.pageBuilderStateStore.setElement(null)
907
+ }
908
+
909
+ async restoreDeletedElementToDOM() {
910
+ // Restore the previously deleted element to the DOM
911
+ const restoredHTML = this.getRestoredElement.value
912
+ const parent = this.getParentElement.value
913
+ const nextSibling = this.getNextSibling.value
914
+
915
+ if (restoredHTML && parent) {
916
+ // Create a container and parse the HTML
917
+ const container = document.createElement('div')
918
+ container.innerHTML = restoredHTML
919
+
920
+ // Insert the restored element before its next sibling (or append if null)
921
+ if (container.firstChild) {
922
+ parent.insertBefore(container.firstChild, nextSibling)
923
+ }
924
+ }
925
+
926
+ // Clear restore-related state
927
+ this.pageBuilderStateStore.setParentElement(null)
928
+ this.pageBuilderStateStore.setRestoredElement(null)
929
+ this.pageBuilderStateStore.setNextSibling(null)
930
+ this.pageBuilderStateStore.setComponent(null)
931
+ this.pageBuilderStateStore.setElement(null)
932
+
933
+ // Wait for Vue to finish DOM updates before attaching event listeners
934
+ await nextTick()
935
+ await this.#addListenersToEditableElements()
936
+ }
937
+
938
+ handleRemoveClasses(userSelectedClass: string): void {
939
+ // remove selected class from element
940
+ if (this.getElement.value?.classList.contains(userSelectedClass)) {
941
+ this.getElement.value?.classList.remove(userSelectedClass)
942
+
943
+ this.pageBuilderStateStore.setElement(this.getElement.value)
944
+ this.pageBuilderStateStore.removeClass(userSelectedClass)
945
+ }
866
946
  }
867
947
 
868
948
  // move component
@@ -927,7 +1007,7 @@ export class PageBuilderService {
927
1007
  }
928
1008
 
929
1009
  if (typeof this.getElement.value.innerHTML === 'string') {
930
- await this.nextTick
1010
+ await nextTick()
931
1011
 
932
1012
  // Update text content
933
1013
  this.getElement.value.textContent = textContentVueModel
@@ -1199,11 +1279,31 @@ export class PageBuilderService {
1199
1279
  }
1200
1280
 
1201
1281
  /**
1202
- * Components from DOM JS (not JS DOM). øøø
1203
- * Saving the current DOM state into JS this.getComponents (for example, before saving to localStorage).
1204
- * This function Only copies the current DOM HTML into JS this.getComponents (component.html_code).
1282
+ * Syncs the current DOM state into the in-memory store (getComponents),
1283
+ * but does NOT save to localStorage.
1284
+ */
1285
+ #syncDomToStoreOnly() {
1286
+ const pagebuilder = document.querySelector('#pagebuilder')
1287
+ if (!pagebuilder) return
1288
+
1289
+ const componentsToSave: { html_code: string; id: string | null; title: string }[] = []
1290
+
1291
+ pagebuilder.querySelectorAll('section[data-componentid]').forEach((section) => {
1292
+ const sanitizedSection = this.#cloneAndRemoveSelectionAttributes(section as HTMLElement)
1293
+ componentsToSave.push({
1294
+ html_code: sanitizedSection.outerHTML,
1295
+ id: sanitizedSection.getAttribute('data-componentid'),
1296
+ title: sanitizedSection.getAttribute('data-component-title') || 'Untitled Component',
1297
+ })
1298
+ })
1299
+
1300
+ this.pageBuilderStateStore.setComponents(componentsToSave)
1301
+ }
1302
+
1303
+ /**
1304
+ * Saves the current DOM state (components) to localStorage.
1205
1305
  */
1206
- #domToComponentsSync = async () => {
1306
+ #saveDomComponentsToLocalStorage() {
1207
1307
  const pagebuilder = document.querySelector('#pagebuilder')
1208
1308
  if (!pagebuilder) return
1209
1309
 
@@ -1235,23 +1335,14 @@ export class PageBuilderService {
1235
1335
  if (keyForSavingFromDomToLocal && typeof keyForSavingFromDomToLocal === 'string') {
1236
1336
  localStorage.setItem(keyForSavingFromDomToLocal, JSON.stringify(dataToSave))
1237
1337
  }
1238
-
1239
- // No DOM mutation here!
1240
- await new Promise<void>((resolve) => resolve())
1241
1338
  }
1242
1339
 
1243
- // save to local storage
1244
- async saveComponentsLocalStorage() {
1245
- await this.nextTick
1246
-
1247
- await this.#domToComponentsSync()
1248
- }
1249
-
1250
- async removeItemComponentsLocalStorage() {
1251
- await this.nextTick
1340
+ async removeCurrentComponentsFromLocalStorage() {
1341
+ await nextTick()
1252
1342
 
1253
- if (this.getLocalStorageItemName.value) {
1254
- localStorage.removeItem(this.getLocalStorageItemName.value)
1343
+ const key = this.getLocalStorageItemName.value
1344
+ if (key) {
1345
+ localStorage.removeItem(key)
1255
1346
  }
1256
1347
  }
1257
1348
 
@@ -1436,7 +1527,7 @@ export class PageBuilderService {
1436
1527
 
1437
1528
  // Only apply if an image is staged
1438
1529
  if (this.getApplyImageToSelection.value && this.getApplyImageToSelection.value.src) {
1439
- await this.nextTick
1530
+ await nextTick()
1440
1531
  this.pageBuilderStateStore.setBasePrimaryImage(`${this.getApplyImageToSelection.value.src}`)
1441
1532
 
1442
1533
  await this.handleAutoSave()
@@ -1767,7 +1858,7 @@ export class PageBuilderService {
1767
1858
  await this.#addListenersToEditableElements()
1768
1859
  } catch (error) {
1769
1860
  console.error('Error parsing JSON components:', error)
1770
- this.pageBuilderStateStore.setComponents([])
1861
+ this.deleteAllComponentsFromDOM()
1771
1862
  }
1772
1863
  }
1773
1864
  // Private method to parse HTML components
@@ -1822,86 +1913,146 @@ export class PageBuilderService {
1822
1913
  await this.#addListenersToEditableElements()
1823
1914
  } catch (error) {
1824
1915
  console.error('Error parsing HTML components:', error)
1825
- this.pageBuilderStateStore.setComponents([])
1916
+ this.deleteAllComponentsFromDOM()
1826
1917
  }
1827
1918
  }
1828
1919
 
1829
- /**
1830
- * Mount Components to DOM
1831
- * @param passedData - HTML/JSON string to inject (optional)
1832
- * @param preferLocalStorage - if true, always try localStorage first
1833
- */
1834
1920
  async mountComponentsToDOM(passedData: string): Promise<void> {
1835
- const pagebuilder = document.querySelector('#pagebuilder')
1921
+ const config = this.pageBuilderStateStore.getPageBuilderConfig
1922
+ const formType = config && config.updateOrCreate && config.updateOrCreate.formType
1836
1923
 
1837
- // If #pagebuilder is not present, cache the data and exit
1838
- if (!pagebuilder) {
1839
- this.pendingMountData = passedData
1840
- return
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
+ }
1841
1944
  }
1945
+ }
1842
1946
 
1843
- // Clear the cache if we are mounting now
1844
- this.pendingMountData = null
1947
+ // --- Private helpers ---
1845
1948
 
1846
- this.pageBuilderStateStore.setComponents([])
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
+ }
1847
1958
 
1848
- // On from type update Save Original Post
1849
- if (
1850
- this.pageBuilderStateStore.getPageBuilderConfig &&
1851
- this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
1852
- typeof this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'string' &&
1853
- this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'update' &&
1854
- passedData &&
1855
- !this.originalComponents
1856
- ) {
1959
+ #handleOriginalComponentsForUpdate(passedData: string, formType: string) {
1960
+ if (formType === 'update' && passedData && !this.originalComponents) {
1961
+ console.log('mountComponentsToDOM ran: m3')
1857
1962
  this.originalComponents = passedData
1858
1963
  }
1964
+ }
1859
1965
 
1860
- // Form type Update
1861
- if (
1862
- this.pageBuilderStateStore.getPageBuilderConfig &&
1863
- this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
1864
- typeof this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'string' &&
1865
- this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'update'
1866
- ) {
1867
- if (passedData) {
1868
- await this.#setComponentsFromData(passedData)
1869
- return
1870
- }
1966
+ async #handleUpdateFormType(passedData: string, localStorageData: string | false) {
1967
+ if (passedData) {
1968
+ console.log('mountComponentsToDOM ran: m4')
1969
+ await this.#setComponentsFromData(passedData)
1970
+ return
1871
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
+ }
1872
1981
 
1873
- // Form type Create
1874
- const localStorageData = this.loadStoredComponentsFromStorage()
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
+ }
1875
1994
 
1876
- if (
1877
- this.pageBuilderStateStore.getPageBuilderConfig &&
1878
- this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
1879
- typeof this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'string' &&
1880
- this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'create'
1881
- ) {
1882
- if (localStorageData) {
1883
- await this.#setComponentsFromData(localStorageData)
1884
- return
1885
- }
1995
+ #isCreateFormType(formType: string): boolean {
1996
+ return formType === 'create'
1997
+ }
1998
+
1999
+ #isUpdateFormType(formType: string): boolean {
2000
+ return formType === 'update'
2001
+ }
1886
2002
 
1887
- // If no localStorage, but passedData exists (for demo), use it
1888
- if (passedData) {
1889
- await this.#setComponentsFromData(passedData)
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
1890
2023
  return
1891
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()
1892
2031
  }
1893
2032
  }
1894
2033
 
1895
- statuspendingMountData(): string | null {
1896
- return this.pendingMountData
1897
- }
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
1898
2040
 
1899
- // Try re-mounting
1900
- async tryMountPendingData() {
1901
- if (this.pendingMountData && document.querySelector('#pagebuilder')) {
1902
- await this.mountComponentsToDOM(this.pendingMountData)
1903
- this.pendingMountData = null
1904
- this.completeBuilderInitialization()
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('')
1905
2056
  }
1906
2057
  }
1907
2058