@myissue/vue-website-page-builder 3.2.93 → 3.2.94

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myissue/vue-website-page-builder",
3
- "version": "v3.2.93",
3
+ "version": "v3.2.94",
4
4
  "description": "Vue 3 page builder component with drag & drop functionality.",
5
5
  "type": "module",
6
6
  "main": "./dist/vue-website-page-builder.umd.cjs",
@@ -83,7 +83,12 @@ const configPageBuilder = {
83
83
 
84
84
  onMounted(async () => {
85
85
  await pageBuilderService.startBuilder(configPageBuilder)
86
- pageBuilderService.mountComponentsToDOM(JSON.stringify(html))
86
+ //
87
+ //
88
+ //
89
+ // await pageBuilderService.mountComponentsToDOM(JSON.stringify(html))
90
+ // await pageBuilderService.mountComponentsToDOM(JSON.stringify(oldhtmlfromdb))
91
+ await pageBuilderService.mountComponentsToDOM(rawHTML)
87
92
  })
88
93
  </script>
89
94
 
@@ -263,12 +263,17 @@ const ensureBuilderInitialized = function () {
263
263
  }
264
264
 
265
265
  onMounted(async () => {
266
+ // Try to mount any pending data if #pagebuilder is now present
267
+ if (pageBuilderService.statuspendingMountData()) {
268
+ await pageBuilderService.tryMountPendingData()
269
+ }
270
+
266
271
  // Check if Builder started
267
- await delay(5000)
272
+ await delay(6000)
268
273
  ensureBuilderInitialized()
269
274
 
270
275
  // Re-check if Builder started
271
- await delay(5000)
276
+ await delay(6000)
272
277
  ensureBuilderInitialized()
273
278
  })
274
279
  </script>
@@ -36,7 +36,10 @@ export class PageBuilderService {
36
36
  private NoneListernesTags: string[]
37
37
  private delay: (ms?: number) => Promise<void>
38
38
  private hasStartedEditing: boolean = false
39
+ // Hold data from Database or Backend for updated post
39
40
  private originalComponents: string | null = null
41
+ // Holds data to be mounted when #pagebuilder is not yet present in the DOM
42
+ private pendingMountData: string | null = null
40
43
 
41
44
  constructor(pageBuilderStateStore: ReturnType<typeof usePageBuilderStateStore>) {
42
45
  this.nextTick = nextTick()
@@ -90,7 +93,7 @@ export class PageBuilderService {
90
93
  this.delay = delay
91
94
  }
92
95
 
93
- // Load existing content from HTML when in update mode
96
+ // Deselect any selected or hovered elements in the builder UI
94
97
  async clearHtmlSelection(): Promise<void> {
95
98
  this.pageBuilderStateStore.setComponent(null)
96
99
  this.pageBuilderStateStore.setElement(null)
@@ -219,11 +222,12 @@ export class PageBuilderService {
219
222
  // Clean up any old localStorage items related to previous builder sessions
220
223
  this.deleteOldPageBuilderLocalStorage()
221
224
 
222
- // Clear any selected HTML elements in the builder UI
225
+ // Deselect any selected or hovered elements in the builder UI
223
226
  await this.clearHtmlSelection()
224
-
225
- // Attach event listeners to all editable elements in the builder
226
- await this.addListenersToEditableElements()
227
+ // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
228
+ await nextTick()
229
+ // Attach event listeners to all editable elements in the Builder
230
+ await this.#addListenersToEditableElements()
227
231
 
228
232
  // Hide the global loading indicator and mark the builder as started
229
233
  this.pageBuilderStateStore.setIsLoadingGlobal(false)
@@ -366,16 +370,14 @@ export class PageBuilderService {
366
370
  * The function is used to
367
371
  * attach event listeners to each element within a 'section'
368
372
  */
369
- addListenersToEditableElements = async () => {
373
+ #addListenersToEditableElements = async () => {
370
374
  const elementsWithListeners = new WeakSet<Element>()
371
375
 
372
376
  const pagebuilder = document.querySelector('#pagebuilder')
373
-
374
377
  if (!pagebuilder) return
375
378
 
376
- // Wait for any pending DOM updates
379
+ // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
377
380
  await nextTick()
378
- await new Promise((resolve) => requestAnimationFrame(resolve))
379
381
 
380
382
  pagebuilder.querySelectorAll('section *').forEach((element) => {
381
383
  // exclude NoneListernesTags && additional Tags for not listening
@@ -538,10 +540,7 @@ export class PageBuilderService {
538
540
  }
539
541
 
540
542
  async #removeHoveredAndSelected() {
541
- await new Promise((resolve) => requestAnimationFrame(resolve))
542
-
543
543
  const pagebuilder = document.querySelector('#pagebuilder')
544
-
545
544
  if (!pagebuilder) return
546
545
 
547
546
  const hoveredElement = pagebuilder.querySelector('[hovered]')
@@ -557,8 +556,6 @@ export class PageBuilderService {
557
556
  }
558
557
 
559
558
  async #syncCurrentClasses() {
560
- await new Promise((resolve) => requestAnimationFrame(resolve))
561
-
562
559
  // convert classList to array
563
560
  const classListArray = Array.from(this.getElement.value?.classList || [])
564
561
 
@@ -653,7 +650,10 @@ export class PageBuilderService {
653
650
  this.pageBuilderStateStore.setComponent(null)
654
651
  this.pageBuilderStateStore.setElement(null)
655
652
 
656
- await this.addListenersToEditableElements()
653
+ // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
654
+ await nextTick()
655
+ // Attach event listeners to all editable elements in the Builder
656
+ await this.#addListenersToEditableElements()
657
657
  }
658
658
 
659
659
  handleFontWeight(userSelectedFontWeight?: string): void {
@@ -836,8 +836,11 @@ export class PageBuilderService {
836
836
  // Remove the component from the array
837
837
  this.getComponents.value.splice(indexToDelete, 1)
838
838
  this.pageBuilderStateStore.setComponents(this.getComponents.value)
839
+
840
+ // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
839
841
  await nextTick()
840
- await this.addListenersToEditableElements()
842
+ // Attach event listeners to all editable elements in the Builder
843
+ await this.#addListenersToEditableElements()
841
844
 
842
845
  this.pageBuilderStateStore.setComponent(null)
843
846
  this.pageBuilderStateStore.setElement(null)
@@ -963,7 +966,6 @@ export class PageBuilderService {
963
966
  this.pageBuilderStateStore.setElement(null)
964
967
 
965
968
  const pagebuilder = document.querySelector('#pagebuilder')
966
-
967
969
  if (!pagebuilder) return
968
970
 
969
971
  const addedHtmlComponents = ref<string[]>([])
@@ -1341,8 +1343,10 @@ export class PageBuilderService {
1341
1343
  this.mountComponentsToDOM(this.originalComponents)
1342
1344
  }
1343
1345
 
1346
+ // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
1344
1347
  await nextTick()
1345
- await this.addListenersToEditableElements()
1348
+ // Attach event listeners to all editable elements in the Builder
1349
+ await this.#addListenersToEditableElements()
1346
1350
 
1347
1351
  this.pageBuilderStateStore.setIsRestoring(false)
1348
1352
  }
@@ -1604,9 +1608,11 @@ export class PageBuilderService {
1604
1608
  componentArrayAddMethod: this.getComponentArrayAddMethod.value || 'push',
1605
1609
  })
1606
1610
 
1607
- // Wait for the DOM to update before setting event listeners
1611
+ // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
1608
1612
  await nextTick()
1609
- await this.addListenersToEditableElements()
1613
+ // Attach event listeners to all editable elements in the Builder
1614
+ await this.#addListenersToEditableElements()
1615
+
1610
1616
  await this.handleAutoSave()
1611
1617
  } catch (error) {
1612
1618
  console.error('Error adding component:', error)
@@ -1644,18 +1650,18 @@ export class PageBuilderService {
1644
1650
  * @param data - JSON string (e.g., '[{"html_code":"...","id":"123","title":"..."}]')
1645
1651
  * OR HTML string (e.g., '<section data-componentid="123">...</section>')
1646
1652
  */
1647
- #setComponentsFromData(htmlString: string): void {
1653
+ async #setComponentsFromData(htmlString: string): Promise<void> {
1648
1654
  // Auto-detect if input is JSON or HTML
1649
1655
  const trimmedData = htmlString.trim()
1650
1656
 
1651
1657
  if (trimmedData.startsWith('[') || trimmedData.startsWith('{')) {
1652
1658
  // Looks like JSON - parse as JSON
1653
- this.#parseJSONComponents(trimmedData)
1659
+ await this.#parseJSONComponents(trimmedData)
1654
1660
  } else if (trimmedData.startsWith('<')) {
1655
1661
  // Looks like HTML - parse as HTML
1656
- this.#parseHTMLComponents(trimmedData)
1662
+ await this.#parseHTMLComponents(trimmedData)
1657
1663
  } else {
1658
- this.#parseJSONComponents(trimmedData)
1664
+ await this.#parseJSONComponents(trimmedData)
1659
1665
  }
1660
1666
  }
1661
1667
 
@@ -1712,15 +1718,17 @@ export class PageBuilderService {
1712
1718
 
1713
1719
  this.pageBuilderStateStore.setComponents(savedCurrentDesign)
1714
1720
 
1715
- await this.clearHtmlSelection()
1716
- await this.addListenersToEditableElements()
1721
+ // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
1722
+ await nextTick()
1723
+ // Attach event listeners to all editable elements in the Builder
1724
+ await this.#addListenersToEditableElements()
1717
1725
  } catch (error) {
1718
1726
  console.error('Error parsing JSON components:', error)
1719
1727
  this.pageBuilderStateStore.setComponents([])
1720
1728
  }
1721
1729
  }
1722
1730
  // Private method to parse HTML components
1723
- #parseHTMLComponents(htmlData: string): void {
1731
+ async #parseHTMLComponents(htmlData: string): Promise<void> {
1724
1732
  try {
1725
1733
  const parser = new DOMParser()
1726
1734
  const doc = parser.parseFromString(htmlData, 'text/html')
@@ -1730,6 +1738,14 @@ export class PageBuilderService {
1730
1738
 
1731
1739
  const extractedSections: ComponentObject[] = []
1732
1740
  sectionElements.forEach((section) => {
1741
+ // Process all elements inside section to add prefix to classes
1742
+ section.querySelectorAll('[class]').forEach((el) => {
1743
+ el.setAttribute(
1744
+ 'class',
1745
+ this.#addTailwindPrefixToClasses(el.getAttribute('class') || '', 'pbx-'),
1746
+ )
1747
+ })
1748
+
1733
1749
  const htmlElement = section as HTMLElement
1734
1750
 
1735
1751
  // Ensure data-componentid exists
@@ -1754,6 +1770,13 @@ export class PageBuilderService {
1754
1770
  })
1755
1771
 
1756
1772
  this.pageBuilderStateStore.setComponents(extractedSections)
1773
+
1774
+ // Deselect any selected or hovered elements in the builder UI
1775
+ await this.clearHtmlSelection()
1776
+ // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
1777
+ await nextTick()
1778
+ // Attach event listeners to all editable elements in the Builder
1779
+ await this.#addListenersToEditableElements()
1757
1780
  } catch (error) {
1758
1781
  console.error('Error parsing HTML components:', error)
1759
1782
  this.pageBuilderStateStore.setComponents([])
@@ -1765,9 +1788,21 @@ export class PageBuilderService {
1765
1788
  * @param passedData - HTML/JSON string to inject (optional)
1766
1789
  * @param preferLocalStorage - if true, always try localStorage first
1767
1790
  */
1768
- mountComponentsToDOM(passedData: string): void {
1769
- // Save the original content only once, in update mode, and only if passedData is provided
1770
- // Form type Update
1791
+ async mountComponentsToDOM(passedData: string): Promise<void> {
1792
+ const pagebuilder = document.querySelector('#pagebuilder')
1793
+
1794
+ // If #pagebuilder is not present, cache the data and exit
1795
+ if (!pagebuilder) {
1796
+ this.pendingMountData = passedData
1797
+ return
1798
+ }
1799
+
1800
+ // Clear the cache if we are mounting now
1801
+ this.pendingMountData = null
1802
+
1803
+ this.pageBuilderStateStore.setComponents([])
1804
+
1805
+ // On from type update Save Original Post
1771
1806
  if (
1772
1807
  this.pageBuilderStateStore.getPageBuilderConfig &&
1773
1808
  this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
@@ -1779,10 +1814,6 @@ export class PageBuilderService {
1779
1814
  this.originalComponents = passedData
1780
1815
  }
1781
1816
 
1782
- this.pageBuilderStateStore.setComponents([])
1783
-
1784
- if (!this.pageBuilderStateStore.getPageBuilderConfig) return
1785
-
1786
1817
  // Form type Update
1787
1818
  if (
1788
1819
  this.pageBuilderStateStore.getPageBuilderConfig &&
@@ -1791,7 +1822,7 @@ export class PageBuilderService {
1791
1822
  this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'update'
1792
1823
  ) {
1793
1824
  if (passedData) {
1794
- this.#setComponentsFromData(passedData)
1825
+ await this.#setComponentsFromData(passedData)
1795
1826
  return
1796
1827
  }
1797
1828
  }
@@ -1806,29 +1837,47 @@ export class PageBuilderService {
1806
1837
  this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'create'
1807
1838
  ) {
1808
1839
  if (localStorageData) {
1809
- this.#setComponentsFromData(localStorageData)
1840
+ await this.#setComponentsFromData(localStorageData)
1810
1841
  return
1811
1842
  }
1812
1843
 
1813
1844
  // If no localStorage, but passedData exists (for demo), use it
1814
1845
  if (passedData) {
1815
- this.#setComponentsFromData(passedData)
1846
+ await this.#setComponentsFromData(passedData)
1816
1847
  return
1817
1848
  }
1818
1849
  }
1819
1850
  }
1820
1851
 
1852
+ statuspendingMountData(): string | null {
1853
+ return this.pendingMountData
1854
+ }
1855
+
1856
+ // Try re-mounting
1857
+ async tryMountPendingData() {
1858
+ if (this.pendingMountData && document.querySelector('#pagebuilder')) {
1859
+ await this.mountComponentsToDOM(this.pendingMountData)
1860
+ this.pendingMountData = null
1861
+ }
1862
+ }
1863
+
1821
1864
  async toggleTipTapModal(status: boolean): Promise<void> {
1822
1865
  this.pageBuilderStateStore.setShowModalTipTap(status)
1823
1866
 
1867
+ // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
1868
+ await nextTick()
1869
+ // Attach event listeners to all editable elements in the Builder
1870
+ await this.#addListenersToEditableElements()
1871
+
1824
1872
  if (!status) {
1825
1873
  await this.handleAutoSave()
1826
1874
  }
1827
1875
  }
1828
1876
 
1829
1877
  async initializeElementStyles(): Promise<void> {
1830
- if (!this.pageBuilderStateStore.getPageBuilderConfig) return
1831
- await new Promise((resolve) => requestAnimationFrame(resolve))
1878
+ // Wait for Vue to finish DOM updates before attaching event listeners.
1879
+ // This ensure elements exist in the DOM.
1880
+ await nextTick()
1832
1881
 
1833
1882
  // handle custom URL
1834
1883
  this.handleHyperlink(undefined, null, false)
@@ -18,7 +18,7 @@ export function initPageBuilder(): PageBuilderService {
18
18
  export function getPageBuilder(): PageBuilderService {
19
19
  if (!instance) {
20
20
  throw new Error(
21
- 'PageBuilderService has not been created. Please call createPageBuilder() first in your App.vue or setup file.',
21
+ 'PageBuilderService has not been created. Please call initPageBuilder() first in your App.vue or setup file.',
22
22
  )
23
23
  }
24
24
  return instance