@myissue/vue-website-page-builder 3.2.96 → 3.3.11

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.96",
3
+ "version": "v3.3.11",
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",
@@ -17,7 +17,7 @@
17
17
  </div>
18
18
  <div
19
19
  :class="[expanded ? 'pbx-block' : 'pbx-hidden']"
20
- class="pbx-px-4 pbx-ease-linear pbx-duration-75"
20
+ class="pbx-px-4 pbx-ease-linear pbx-duration-75 pbx-pb-8"
21
21
  >
22
22
  <slot name="content" />
23
23
  </div>
@@ -83,12 +83,9 @@ const configPageBuilder = {
83
83
 
84
84
  onMounted(async () => {
85
85
  await pageBuilderService.startBuilder(configPageBuilder)
86
- //
87
- //
88
- //
89
- // await pageBuilderService.mountComponentsToDOM(JSON.stringify(html))
86
+ await pageBuilderService.mountComponentsToDOM(JSON.stringify(html))
90
87
  // await pageBuilderService.mountComponentsToDOM(JSON.stringify(oldhtmlfromdb))
91
- await pageBuilderService.mountComponentsToDOM(rawHTML)
88
+ // await pageBuilderService.mountComponentsToDOM(rawHTML)
92
89
  })
93
90
  </script>
94
91
 
@@ -169,9 +169,6 @@ const getIsSaving = computed(() => {
169
169
  })
170
170
 
171
171
  const getIsLoadingResumeEditing = computed(() => {
172
- if (pageBuilderStateStore.getIsLoadingResumeEditing) {
173
- handlerRumeEditingForUpdate()
174
- }
175
172
  return pageBuilderStateStore.getIsLoadingResumeEditing
176
173
  })
177
174
  const getIsRestoring = computed(() => {
@@ -263,17 +260,14 @@ const ensureBuilderInitialized = function () {
263
260
  }
264
261
 
265
262
  onMounted(async () => {
266
- // Try to mount any pending data if #pagebuilder is now present
267
- if (pageBuilderService.statuspendingMountData()) {
268
- await pageBuilderService.tryMountPendingData()
269
- }
263
+ await pageBuilderService.tryMountPendingData()
270
264
 
271
265
  // Check if Builder started
272
- await delay(6000)
266
+ await delay(10000)
273
267
  ensureBuilderInitialized()
274
268
 
275
269
  // Re-check if Builder started
276
- await delay(6000)
270
+ await delay(10000)
277
271
  ensureBuilderInitialized()
278
272
  })
279
273
  </script>
@@ -195,10 +195,20 @@ export class PageBuilderService {
195
195
  }
196
196
 
197
197
  /**
198
- * Initializes the Page Builder with the provided configuration.
199
- * Handles config validation, local storage, and sets up the builder state.
198
+ * - Entry point for initializing the Page Builder.
199
+ * - Sets the builder as started in the state store.
200
+ * - Shows a global loading indicator.
201
+ * - Stores and validates the provided configuration.
202
+ * - Updates the localStorage key name based on the config/resource.
203
+ * - Completes builder initialization if the DOM is ready.
204
+ *
205
+ * @param config - The configuration object for the Page Builder.
200
206
  */
201
207
  async startBuilder(config: PageBuilderConfig): Promise<void> {
208
+ // Reactive flag signals to the UI that the builder has been successfully initialized
209
+ // Prevents builder actions to prevent errors caused by missing DOM .
210
+ this.pageBuilderStateStore.setBuilderStarted(true)
211
+
202
212
  // Show a global loading indicator while initializing
203
213
  this.pageBuilderStateStore.setIsLoadingGlobal(true)
204
214
 
@@ -213,25 +223,35 @@ export class PageBuilderService {
213
223
  // Update the localStorage key name based on the config/resource
214
224
  this.#updateLocalStorageItemName()
215
225
 
216
- this.#completeBuilderInitialization()
217
- }
226
+ this.completeBuilderInitialization()
218
227
 
219
- async #completeBuilderInitialization() {
220
- this.pageBuilderStateStore.setIsLoadingGlobal(true)
228
+ const formType = config.updateOrCreate && config.updateOrCreate.formType
229
+ if (formType === 'create') {
230
+ await this.mountComponentsToDOM('')
231
+ }
232
+ }
221
233
 
234
+ async completeBuilderInitialization() {
222
235
  const pagebuilder = document.querySelector('#pagebuilder')
223
236
  if (!pagebuilder) return
224
237
 
238
+ // Deselect any selected or hovered elements in the builder UI
239
+ await this.clearHtmlSelection()
240
+ this.pageBuilderStateStore.setIsLoadingGlobal(true)
225
241
  await this.delay(300)
226
242
 
227
243
  // Hide the global loading indicator and mark the builder as started
228
244
  this.pageBuilderStateStore.setIsLoadingGlobal(false)
229
- this.pageBuilderStateStore.setBuilderStarted(true)
230
245
 
231
- // If there is a local draft for this resource, mark it in the state
232
246
  if (await this.hasLocalDraftForUpdate()) {
233
247
  this.pageBuilderStateStore.setHasLocalDraftForUpdate(true)
234
248
  }
249
+
250
+ // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
251
+ await nextTick()
252
+ // Attach event listeners to all editable elements in the Builder
253
+ await this.#addListenersToEditableElements()
254
+
235
255
  // Clean up any old localStorage items related to previous builder sessions
236
256
  this.deleteOldPageBuilderLocalStorage()
237
257
  }
@@ -415,6 +435,8 @@ export class PageBuilderService {
415
435
 
416
436
  try {
417
437
  this.pageBuilderStateStore.setIsSaving(true)
438
+ // Deselect any selected or hovered elements in the builder UI
439
+ //
418
440
  await this.saveComponentsLocalStorage()
419
441
  await this.delay(500)
420
442
  } catch (err) {
@@ -1163,7 +1185,26 @@ export class PageBuilderService {
1163
1185
  }
1164
1186
 
1165
1187
  /**
1166
- * Components from DOM JS (not JS DOM).
1188
+ * Returns a clone of the given element with [hovered] and [selected] attributes
1189
+ * removed from itself and all descendants. Does NOT mutate the live DOM.
1190
+ * @param element The HTMLElement to clone and sanitize
1191
+ */
1192
+ #cloneAndRemoveSelectionAttributes(element: HTMLElement): HTMLElement {
1193
+ // Deep clone the element
1194
+ const clone = element.cloneNode(true) as HTMLElement
1195
+
1196
+ // Remove [hovered] and [selected] from the clone and all descendants
1197
+ clone.querySelectorAll('[hovered]').forEach((el) => el.removeAttribute('hovered'))
1198
+ clone.querySelectorAll('[selected]').forEach((el) => el.removeAttribute('selected'))
1199
+ // Also remove from the root element itself if present
1200
+ clone.removeAttribute('hovered')
1201
+ clone.removeAttribute('selected')
1202
+
1203
+ return clone
1204
+ }
1205
+
1206
+ /**
1207
+ * Components from DOM → JS (not JS → DOM). øøø
1167
1208
  * Saving the current DOM state into JS this.getComponents (for example, before saving to localStorage).
1168
1209
  * This function Only copies the current DOM HTML into JS this.getComponents (component.html_code).
1169
1210
  */
@@ -1179,10 +1220,12 @@ export class PageBuilderService {
1179
1220
  const componentsToSave: { html_code: string; id: string | null; title: string }[] = []
1180
1221
 
1181
1222
  pagebuilder.querySelectorAll('section[data-componentid]').forEach((section) => {
1223
+ const sanitizedSection = this.#cloneAndRemoveSelectionAttributes(section as HTMLElement)
1224
+
1182
1225
  componentsToSave.push({
1183
- html_code: section.outerHTML,
1184
- id: section.getAttribute('data-componentid'),
1185
- title: section.getAttribute('data-component-title') || 'Untitled Component',
1226
+ html_code: sanitizedSection.outerHTML,
1227
+ id: sanitizedSection.getAttribute('data-componentid'),
1228
+ title: sanitizedSection.getAttribute('data-component-title') || 'Untitled Component',
1186
1229
  })
1187
1230
  })
1188
1231
 
@@ -1291,8 +1334,8 @@ export class PageBuilderService {
1291
1334
  const draft = localStorage.getItem(key)
1292
1335
  if (draft) {
1293
1336
  try {
1294
- await this.delay(1000)
1295
-
1337
+ await this.delay(500)
1338
+ this.pageBuilderStateStore.setHasLocalDraftForUpdate(false)
1296
1339
  return true
1297
1340
  } catch (err) {
1298
1341
  console.error('Unable to mount components to DOM.', err)
@@ -1359,6 +1402,7 @@ export class PageBuilderService {
1359
1402
  getStorageItemNameForResource(): string | null {
1360
1403
  return this.getLocalStorageItemName.value
1361
1404
  }
1405
+
1362
1406
  loadStoredComponentsFromStorage() {
1363
1407
  if (!this.getLocalStorageItemName.value) return false
1364
1408
 
@@ -1797,7 +1841,14 @@ export class PageBuilderService {
1797
1841
 
1798
1842
  // If #pagebuilder is not present, cache the data and exit
1799
1843
  if (!pagebuilder) {
1800
- this.pendingMountData = passedData
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
1851
+ }
1801
1852
  return
1802
1853
  }
1803
1854
 
@@ -1853,16 +1904,34 @@ export class PageBuilderService {
1853
1904
  }
1854
1905
  }
1855
1906
 
1856
- statuspendingMountData(): string | null {
1857
- return this.pendingMountData
1858
- }
1859
-
1860
- // Try re-mounting
1861
1907
  async tryMountPendingData() {
1862
- if (this.pendingMountData && document.querySelector('#pagebuilder')) {
1908
+ const pagebuilder = document.querySelector('#pagebuilder')
1909
+
1910
+ // Only run if #pagebuilder exists
1911
+ if (!pagebuilder) return
1912
+
1913
+ // If pendingMountData is a non-empty string (update or demo), always mount
1914
+ if (this.pendingMountData && typeof this.pendingMountData === 'string') {
1863
1915
  await this.mountComponentsToDOM(this.pendingMountData)
1864
1916
  this.pendingMountData = null
1865
- this.#completeBuilderInitialization()
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
+ const config = this.pageBuilderStateStore.getPageBuilderConfig
1923
+ const formType = config && config.updateOrCreate && config.updateOrCreate.formType
1924
+ const components = this.pageBuilderStateStore.getComponents
1925
+
1926
+ if (
1927
+ this.pendingMountData === '' &&
1928
+ formType === 'create' &&
1929
+ (!components || (Array.isArray(components) && components.length === 0))
1930
+ ) {
1931
+ await this.mountComponentsToDOM('')
1932
+ this.pendingMountData = null
1933
+ this.completeBuilderInitialization()
1934
+ return
1866
1935
  }
1867
1936
  }
1868
1937