@myissue/vue-website-page-builder 3.3.11 → 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,15 +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()
227
-
228
269
  const formType = config.updateOrCreate && config.updateOrCreate.formType
229
270
  if (formType === 'create') {
230
271
  await this.mountComponentsToDOM('')
231
272
  }
232
273
  }
233
274
 
234
- async completeBuilderInitialization() {
275
+ async #completeBuilderInitialization() {
276
+ console.log('complete builder..')
235
277
  const pagebuilder = document.querySelector('#pagebuilder')
236
278
  if (!pagebuilder) return
237
279
 
@@ -437,7 +479,7 @@ export class PageBuilderService {
437
479
  this.pageBuilderStateStore.setIsSaving(true)
438
480
  // Deselect any selected or hovered elements in the builder UI
439
481
  //
440
- await this.saveComponentsLocalStorage()
482
+ this.#saveDomComponentsToLocalStorage()
441
483
  await this.delay(500)
442
484
  } catch (err) {
443
485
  console.error('Error trying auto save.', err)
@@ -449,7 +491,7 @@ export class PageBuilderService {
449
491
  if (passedConfig && !passedConfig.userSettings) {
450
492
  try {
451
493
  this.pageBuilderStateStore.setIsSaving(true)
452
- await this.saveComponentsLocalStorage()
494
+ this.#saveDomComponentsToLocalStorage()
453
495
  await this.delay(300)
454
496
  } catch (err) {
455
497
  console.error('Error trying saving.', err)
@@ -475,7 +517,7 @@ export class PageBuilderService {
475
517
  passedConfig.userSettings.autoSave)
476
518
  ) {
477
519
  this.pageBuilderStateStore.setIsSaving(true)
478
- await this.saveComponentsLocalStorage()
520
+ this.#saveDomComponentsToLocalStorage()
479
521
  await this.delay(300)
480
522
 
481
523
  this.pageBuilderStateStore.setIsSaving(false)
@@ -483,7 +525,7 @@ export class PageBuilderService {
483
525
  }
484
526
  if (passedConfig && !passedConfig.userSettings) {
485
527
  this.pageBuilderStateStore.setIsSaving(true)
486
- await this.saveComponentsLocalStorage()
528
+ this.#saveDomComponentsToLocalStorage()
487
529
  await this.delay(300)
488
530
 
489
531
  this.pageBuilderStateStore.setIsSaving(false)
@@ -494,15 +536,16 @@ export class PageBuilderService {
494
536
  // Deep clone clone component
495
537
  const clonedComponent = { ...componentObject }
496
538
 
539
+ const pageBuilder = document.querySelector('#contains-pagebuilder')
497
540
  // scoll to top or bottom # end
498
- if (this.containsPagebuilder) {
541
+ if (pageBuilder) {
499
542
  if (
500
543
  this.getComponentArrayAddMethod.value === 'unshift' ||
501
544
  this.getComponentArrayAddMethod.value === 'push'
502
545
  ) {
503
546
  // push to top
504
547
  if (this.getComponentArrayAddMethod.value === 'unshift') {
505
- this.containsPagebuilder.scrollTo({
548
+ pageBuilder.scrollTo({
506
549
  top: 0,
507
550
  behavior: 'smooth',
508
551
  })
@@ -510,9 +553,8 @@ export class PageBuilderService {
510
553
 
511
554
  // push to bottom
512
555
  if (this.getComponentArrayAddMethod.value === 'push') {
513
- const maxHeight = this.containsPagebuilder.scrollHeight
514
- this.containsPagebuilder.scrollTo({
515
- top: maxHeight,
556
+ pageBuilder.scrollTo({
557
+ top: 0,
516
558
  behavior: 'smooth',
517
559
  })
518
560
  }
@@ -606,80 +648,6 @@ export class PageBuilderService {
606
648
  }
607
649
  }
608
650
 
609
- handleRemoveClasses(userSelectedClass: string): void {
610
- // remove selected class from element
611
- if (this.getElement.value?.classList.contains(userSelectedClass)) {
612
- this.getElement.value?.classList.remove(userSelectedClass)
613
-
614
- this.pageBuilderStateStore.setElement(this.getElement.value)
615
- this.pageBuilderStateStore.removeClass(userSelectedClass)
616
- }
617
- }
618
-
619
- handleDeleteElement() {
620
- // Get the element to be deleted
621
- const element = this.getElement.value
622
-
623
- if (!element) return
624
-
625
- if (!element?.parentNode) {
626
- this.pageBuilderStateStore.setComponent(null)
627
- this.pageBuilderStateStore.setElement(null)
628
- return
629
- }
630
-
631
- // Store the parent of the deleted element
632
- // if parent element tag is section remove the hole component
633
- if (element.parentElement?.tagName !== 'SECTION') {
634
- this.pageBuilderStateStore.setParentElement(element.parentNode as HTMLElement)
635
-
636
- // Store the outerHTML of the deleted element
637
- this.pageBuilderStateStore.setRestoredElement(element.outerHTML)
638
-
639
- // Store the next sibling of the deleted element
640
- this.pageBuilderStateStore.setNextSibling(element.nextSibling as HTMLElement | null)
641
- }
642
-
643
- // if parent element tag is section remove the hole component
644
- if (element.parentElement?.tagName === 'SECTION') {
645
- this.deleteSelectedComponent()
646
- }
647
-
648
- // Remove the element from the DOM
649
- element.remove()
650
- this.pageBuilderStateStore.setComponent(null)
651
- this.pageBuilderStateStore.setElement(null)
652
- }
653
-
654
- async handleRestoreElement() {
655
- // Get the stored deleted element and its parent
656
- if (this.getRestoredElement.value && this.getParentElement.value) {
657
- // Create a new element from the stored outerHTML
658
- const newElement = document.createElement('div')
659
- // Fixed type conversion issue
660
- newElement.innerHTML = this.getRestoredElement.value
661
-
662
- // Append the restored element to its parent
663
- // Insert the restored element before its next sibling in its parent
664
- if (newElement.firstChild && this.getParentElement.value) {
665
- // insertBefore can accept null as second parameter (will append to end)
666
- this.getParentElement.value.insertBefore(newElement.firstChild, this.getNextSibling.value)
667
- }
668
- }
669
-
670
- // Clear
671
- this.pageBuilderStateStore.setParentElement(null)
672
- this.pageBuilderStateStore.setRestoredElement(null)
673
- this.pageBuilderStateStore.setNextSibling(null)
674
- this.pageBuilderStateStore.setComponent(null)
675
- this.pageBuilderStateStore.setElement(null)
676
-
677
- // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
678
- await nextTick()
679
- // Attach event listeners to all editable elements in the Builder
680
- await this.#addListenersToEditableElements()
681
- }
682
-
683
651
  handleFontWeight(userSelectedFontWeight?: string): void {
684
652
  this.#applyElementClassChanges(
685
653
  userSelectedFontWeight,
@@ -840,15 +808,40 @@ export class PageBuilderService {
840
808
  this.#applyElementClassChanges(opacity, tailwindOpacities.opacities, 'setOpacity')
841
809
  }
842
810
 
843
- 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
844
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
+ }
845
833
  }
846
834
 
847
- async deleteSelectedComponent() {
848
- 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
849
842
 
850
843
  // Find the index of the component to delete
851
- const indexToDelete = this.getComponents.value.findIndex(
844
+ const indexToDelete = components.findIndex(
852
845
  (component) => component.id === this.getComponent.value?.id,
853
846
  )
854
847
 
@@ -857,17 +850,99 @@ export class PageBuilderService {
857
850
  return
858
851
  }
859
852
 
860
- // Remove the component from the array
861
- this.getComponents.value.splice(indexToDelete, 1)
862
- 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
+ ]
863
858
 
864
- // 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.
865
871
  await nextTick()
866
- // Attach event listeners to all editable elements in the Builder
867
872
  await this.#addListenersToEditableElements()
868
873
 
869
874
  this.pageBuilderStateStore.setComponent(null)
870
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
+ }
871
946
  }
872
947
 
873
948
  // move component
@@ -932,7 +1007,7 @@ export class PageBuilderService {
932
1007
  }
933
1008
 
934
1009
  if (typeof this.getElement.value.innerHTML === 'string') {
935
- await this.nextTick
1010
+ await nextTick()
936
1011
 
937
1012
  // Update text content
938
1013
  this.getElement.value.textContent = textContentVueModel
@@ -1204,11 +1279,31 @@ export class PageBuilderService {
1204
1279
  }
1205
1280
 
1206
1281
  /**
1207
- * Components from DOM JS (not JS DOM). øøø
1208
- * Saving the current DOM state into JS this.getComponents (for example, before saving to localStorage).
1209
- * 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.
1210
1305
  */
1211
- #domToComponentsSync = async () => {
1306
+ #saveDomComponentsToLocalStorage() {
1212
1307
  const pagebuilder = document.querySelector('#pagebuilder')
1213
1308
  if (!pagebuilder) return
1214
1309
 
@@ -1240,23 +1335,14 @@ export class PageBuilderService {
1240
1335
  if (keyForSavingFromDomToLocal && typeof keyForSavingFromDomToLocal === 'string') {
1241
1336
  localStorage.setItem(keyForSavingFromDomToLocal, JSON.stringify(dataToSave))
1242
1337
  }
1243
-
1244
- // No DOM mutation here!
1245
- await new Promise<void>((resolve) => resolve())
1246
- }
1247
-
1248
- // save to local storage
1249
- async saveComponentsLocalStorage() {
1250
- await this.nextTick
1251
-
1252
- await this.#domToComponentsSync()
1253
1338
  }
1254
1339
 
1255
- async removeItemComponentsLocalStorage() {
1256
- await this.nextTick
1340
+ async removeCurrentComponentsFromLocalStorage() {
1341
+ await nextTick()
1257
1342
 
1258
- if (this.getLocalStorageItemName.value) {
1259
- localStorage.removeItem(this.getLocalStorageItemName.value)
1343
+ const key = this.getLocalStorageItemName.value
1344
+ if (key) {
1345
+ localStorage.removeItem(key)
1260
1346
  }
1261
1347
  }
1262
1348
 
@@ -1441,7 +1527,7 @@ export class PageBuilderService {
1441
1527
 
1442
1528
  // Only apply if an image is staged
1443
1529
  if (this.getApplyImageToSelection.value && this.getApplyImageToSelection.value.src) {
1444
- await this.nextTick
1530
+ await nextTick()
1445
1531
  this.pageBuilderStateStore.setBasePrimaryImage(`${this.getApplyImageToSelection.value.src}`)
1446
1532
 
1447
1533
  await this.handleAutoSave()
@@ -1772,7 +1858,7 @@ export class PageBuilderService {
1772
1858
  await this.#addListenersToEditableElements()
1773
1859
  } catch (error) {
1774
1860
  console.error('Error parsing JSON components:', error)
1775
- this.pageBuilderStateStore.setComponents([])
1861
+ this.deleteAllComponentsFromDOM()
1776
1862
  }
1777
1863
  }
1778
1864
  // Private method to parse HTML components
@@ -1827,111 +1913,146 @@ export class PageBuilderService {
1827
1913
  await this.#addListenersToEditableElements()
1828
1914
  } catch (error) {
1829
1915
  console.error('Error parsing HTML components:', error)
1830
- this.pageBuilderStateStore.setComponents([])
1916
+ this.deleteAllComponentsFromDOM()
1831
1917
  }
1832
1918
  }
1833
1919
 
1834
- /**
1835
- * Mount Components to DOM
1836
- * @param passedData - HTML/JSON string to inject (optional)
1837
- * @param preferLocalStorage - if true, always try localStorage first
1838
- */
1839
1920
  async mountComponentsToDOM(passedData: string): Promise<void> {
1840
- const pagebuilder = document.querySelector('#pagebuilder')
1921
+ const config = this.pageBuilderStateStore.getPageBuilderConfig
1922
+ const formType = config && config.updateOrCreate && config.updateOrCreate.formType
1841
1923
 
1842
- // If #pagebuilder is not present, cache the data and exit
1843
- if (!pagebuilder) {
1844
- // For 'create', set pendingMountData to '' (empty string)
1845
- const config = this.pageBuilderStateStore.getPageBuilderConfig
1846
- const formType = config && config.updateOrCreate && config.updateOrCreate.formType
1847
- if (formType === 'create') {
1848
- this.pendingMountData = ''
1849
- } else {
1850
- this.pendingMountData = passedData
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
1851
1943
  }
1852
- return
1853
1944
  }
1945
+ }
1854
1946
 
1855
- // Clear the cache if we are mounting now
1856
- this.pendingMountData = null
1947
+ // --- Private helpers ---
1857
1948
 
1858
- 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
+ }
1859
1958
 
1860
- // On from type update Save Original Post
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
- passedData &&
1867
- !this.originalComponents
1868
- ) {
1959
+ #handleOriginalComponentsForUpdate(passedData: string, formType: string) {
1960
+ if (formType === 'update' && passedData && !this.originalComponents) {
1961
+ console.log('mountComponentsToDOM ran: m3')
1869
1962
  this.originalComponents = passedData
1870
1963
  }
1964
+ }
1871
1965
 
1872
- // Form type Update
1873
- if (
1874
- this.pageBuilderStateStore.getPageBuilderConfig &&
1875
- this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
1876
- typeof this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'string' &&
1877
- this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'update'
1878
- ) {
1879
- if (passedData) {
1880
- await this.#setComponentsFromData(passedData)
1881
- return
1882
- }
1966
+ async #handleUpdateFormType(passedData: string, localStorageData: string | false) {
1967
+ if (passedData) {
1968
+ console.log('mountComponentsToDOM ran: m4')
1969
+ await this.#setComponentsFromData(passedData)
1970
+ return
1971
+ }
1972
+ if (localStorageData) {
1973
+ console.log('mountComponentsToDOM ran: m5')
1974
+ await this.#setComponentsFromData(localStorageData)
1975
+ return
1883
1976
  }
1977
+ // If nothing, clear components
1978
+ console.log('mountComponentsToDOM ran: m6')
1979
+ this.deleteAllComponentsFromDOM()
1980
+ }
1884
1981
 
1885
- // Form type Create
1886
- 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
+ }
1887
1994
 
1888
- if (
1889
- this.pageBuilderStateStore.getPageBuilderConfig &&
1890
- this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
1891
- typeof this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'string' &&
1892
- this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'create'
1893
- ) {
1894
- if (localStorageData) {
1895
- await this.#setComponentsFromData(localStorageData)
1896
- return
1897
- }
1995
+ #isCreateFormType(formType: string): boolean {
1996
+ return formType === 'create'
1997
+ }
1898
1998
 
1899
- // If no localStorage, but passedData exists (for demo), use it
1900
- if (passedData) {
1901
- await this.#setComponentsFromData(passedData)
1999
+ #isUpdateFormType(formType: string): boolean {
2000
+ return formType === 'update'
2001
+ }
2002
+
2003
+ async ensureBuilderInitializedForCreate() {
2004
+ const pagebuilder = document.querySelector('#pagebuilder')
2005
+ if (!pagebuilder) return
2006
+
2007
+ const config = this.pageBuilderStateStore.getPageBuilderConfig
2008
+ console.log('den er:', config)
2009
+ const formType = config && config.updateOrCreate && config.updateOrCreate.formType
2010
+
2011
+ if (formType === 'create') {
2012
+ this.#completeBuilderInitialization()
2013
+ await nextTick()
2014
+
2015
+ if (
2016
+ formType === 'create' &&
2017
+ (!this.getComponents.value ||
2018
+ (Array.isArray(this.getComponents.value) && this.getComponents.value.length === 0))
2019
+ ) {
2020
+ console.log('ensureBuilderInitializedForCreate e1')
2021
+ await this.mountComponentsToDOM('')
2022
+ this.pendingMountData = null
1902
2023
  return
1903
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()
1904
2031
  }
1905
2032
  }
1906
2033
 
1907
- async tryMountPendingData() {
2034
+ async ensureBuilderInitializedForUpdate() {
1908
2035
  const pagebuilder = document.querySelector('#pagebuilder')
1909
-
1910
- // Only run if #pagebuilder exists
1911
2036
  if (!pagebuilder) return
1912
2037
 
1913
- // If pendingMountData is a non-empty string (update or demo), always mount
1914
- if (this.pendingMountData && typeof this.pendingMountData === 'string') {
1915
- await this.mountComponentsToDOM(this.pendingMountData)
1916
- this.pendingMountData = null
1917
- this.completeBuilderInitialization()
1918
- return
1919
- }
1920
-
1921
- // If pendingMountData is exactly '', and formType is 'create', and no components are mounted, mount for create
1922
2038
  const config = this.pageBuilderStateStore.getPageBuilderConfig
1923
2039
  const formType = config && config.updateOrCreate && config.updateOrCreate.formType
1924
- const components = this.pageBuilderStateStore.getComponents
1925
2040
 
1926
- if (
1927
- this.pendingMountData === '' &&
1928
- formType === 'create' &&
1929
- (!components || (Array.isArray(components) && components.length === 0))
1930
- ) {
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
1931
2055
  await this.mountComponentsToDOM('')
1932
- this.pendingMountData = null
1933
- this.completeBuilderInitialization()
1934
- return
1935
2056
  }
1936
2057
  }
1937
2058