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

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.95",
3
+ "version": "v3.3.1",
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",
@@ -188,12 +188,7 @@ const openHTMLSettings = function () {
188
188
 
189
189
  <!-- Delete Layout Start -->
190
190
  <button
191
- @click="
192
- () => {
193
- pageBuilderService.clearHtmlSelection()
194
- deleteAllComponents()
195
- }
196
- "
191
+ @click="deleteAllComponents"
197
192
  class="pbx-cursor-pointer lg:pbx-flex pbx-myPrimaryTag pbx-font-normal pbx-w-max pbx-border-none pbx-m-0 pbx-bg-myPrimaryErrorColor pbx-text-white"
198
193
  type="button"
199
194
  >
@@ -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
 
@@ -102,10 +102,6 @@ const handleAddComponent = async function () {
102
102
  // end modal
103
103
  }
104
104
 
105
- const getHasLocalDraftForUpdate = computed(() => {
106
- return pageBuilderStateStore.getHasLocalDraftForUpdate
107
- })
108
-
109
105
  const getElement = computed(() => {
110
106
  return pageBuilderStateStore.getElement
111
107
  })
@@ -114,6 +110,10 @@ const getComponents = computed(() => {
114
110
  return pageBuilderStateStore.getComponents
115
111
  })
116
112
 
113
+ const getHasLocalDraftForUpdate = computed(() => {
114
+ return pageBuilderStateStore.getHasLocalDraftForUpdate
115
+ })
116
+
117
117
  watch(getHasLocalDraftForUpdate, (newVal) => {
118
118
  if (newVal) {
119
119
  handlerRumeEditingForUpdate()
@@ -168,11 +168,8 @@ const getIsSaving = computed(() => {
168
168
  return pageBuilderStateStore.getIsSaving
169
169
  })
170
170
 
171
- const getIsResumeEditing = computed(() => {
172
- if (pageBuilderStateStore.getIsResumeEditing) {
173
- handlerRumeEditingForUpdate()
174
- }
175
- return pageBuilderStateStore.getIsResumeEditing
171
+ const getIsLoadingResumeEditing = computed(() => {
172
+ return pageBuilderStateStore.getIsLoadingResumeEditing
176
173
  })
177
174
  const getIsRestoring = computed(() => {
178
175
  return pageBuilderStateStore.getIsRestoring
@@ -269,11 +266,11 @@ onMounted(async () => {
269
266
  }
270
267
 
271
268
  // Check if Builder started
272
- await delay(6000)
269
+ await delay(10000)
273
270
  ensureBuilderInitialized()
274
271
 
275
272
  // Re-check if Builder started
276
- await delay(6000)
273
+ await delay(10000)
277
274
  ensureBuilderInitialized()
278
275
  })
279
276
  </script>
@@ -340,7 +337,7 @@ onMounted(async () => {
340
337
 
341
338
  <DynamicModalBuilder
342
339
  :showDynamicModalBuilder="showModalResumeEditing"
343
- :isLoading="getIsResumeEditing"
340
+ :isLoading="getIsLoadingResumeEditing"
344
341
  :type="typeModal"
345
342
  :gridColumnAmount="gridColumnModalResumeEditing"
346
343
  :title="titleModalResumeEditing"
@@ -195,15 +195,24 @@ 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
 
205
215
  // Wait briefly to ensure UI updates and async processes settle
206
- await this.delay(300)
207
216
 
208
217
  // Store the provided config in the builder's state store
209
218
  this.pageBuilderStateStore.setPageBuilderConfig(config)
@@ -214,24 +223,32 @@ export class PageBuilderService {
214
223
  // Update the localStorage key name based on the config/resource
215
224
  this.#updateLocalStorageItemName()
216
225
 
217
- // If there is a local draft for this resource, mark it in the state
218
- if (await this.#hasLocalDraftForUpdate()) {
219
- this.pageBuilderStateStore.setHasLocalDraftForUpdate(true)
220
- }
226
+ this.completeBuilderInitialization()
227
+ }
221
228
 
222
- // Clean up any old localStorage items related to previous builder sessions
223
- this.deleteOldPageBuilderLocalStorage()
229
+ async completeBuilderInitialization() {
230
+ const pagebuilder = document.querySelector('#pagebuilder')
231
+ if (!pagebuilder) return
224
232
 
225
233
  // Deselect any selected or hovered elements in the builder UI
226
234
  await this.clearHtmlSelection()
235
+ this.pageBuilderStateStore.setIsLoadingGlobal(true)
236
+ await this.delay(300)
237
+
238
+ // Hide the global loading indicator and mark the builder as started
239
+ this.pageBuilderStateStore.setIsLoadingGlobal(false)
240
+
241
+ if (await this.hasLocalDraftForUpdate()) {
242
+ this.pageBuilderStateStore.setHasLocalDraftForUpdate(true)
243
+ }
244
+
227
245
  // Wait for Vue to finish DOM updates before attaching event listeners. This ensure elements exist in the DOM.
228
246
  await nextTick()
229
247
  // Attach event listeners to all editable elements in the Builder
230
248
  await this.#addListenersToEditableElements()
231
249
 
232
- // Hide the global loading indicator and mark the builder as started
233
- this.pageBuilderStateStore.setIsLoadingGlobal(false)
234
- this.pageBuilderStateStore.setBuilderStarted(true)
250
+ // Clean up any old localStorage items related to previous builder sessions
251
+ this.deleteOldPageBuilderLocalStorage()
235
252
  }
236
253
 
237
254
  #applyElementClassChanges(
@@ -413,6 +430,8 @@ export class PageBuilderService {
413
430
 
414
431
  try {
415
432
  this.pageBuilderStateStore.setIsSaving(true)
433
+ // Deselect any selected or hovered elements in the builder UI
434
+ //
416
435
  await this.saveComponentsLocalStorage()
417
436
  await this.delay(500)
418
437
  } catch (err) {
@@ -1161,7 +1180,26 @@ export class PageBuilderService {
1161
1180
  }
1162
1181
 
1163
1182
  /**
1164
- * Components from DOM JS (not JS DOM).
1183
+ * Returns a clone of the given element with [hovered] and [selected] attributes
1184
+ * removed from itself and all descendants. Does NOT mutate the live DOM.
1185
+ * @param element The HTMLElement to clone and sanitize
1186
+ */
1187
+ #cloneAndRemoveSelectionAttributes(element: HTMLElement): HTMLElement {
1188
+ // Deep clone the element
1189
+ const clone = element.cloneNode(true) as HTMLElement
1190
+
1191
+ // Remove [hovered] and [selected] from the clone and all descendants
1192
+ clone.querySelectorAll('[hovered]').forEach((el) => el.removeAttribute('hovered'))
1193
+ clone.querySelectorAll('[selected]').forEach((el) => el.removeAttribute('selected'))
1194
+ // Also remove from the root element itself if present
1195
+ clone.removeAttribute('hovered')
1196
+ clone.removeAttribute('selected')
1197
+
1198
+ return clone
1199
+ }
1200
+
1201
+ /**
1202
+ * Components from DOM → JS (not JS → DOM). øøø
1165
1203
  * Saving the current DOM state into JS this.getComponents (for example, before saving to localStorage).
1166
1204
  * This function Only copies the current DOM HTML into JS this.getComponents (component.html_code).
1167
1205
  */
@@ -1177,10 +1215,12 @@ export class PageBuilderService {
1177
1215
  const componentsToSave: { html_code: string; id: string | null; title: string }[] = []
1178
1216
 
1179
1217
  pagebuilder.querySelectorAll('section[data-componentid]').forEach((section) => {
1218
+ const sanitizedSection = this.#cloneAndRemoveSelectionAttributes(section as HTMLElement)
1219
+
1180
1220
  componentsToSave.push({
1181
- html_code: section.outerHTML,
1182
- id: section.getAttribute('data-componentid'),
1183
- title: section.getAttribute('data-component-title') || 'Untitled Component',
1221
+ html_code: sanitizedSection.outerHTML,
1222
+ id: sanitizedSection.getAttribute('data-componentid'),
1223
+ title: sanitizedSection.getAttribute('data-component-title') || 'Untitled Component',
1184
1224
  })
1185
1225
  })
1186
1226
 
@@ -1270,7 +1310,12 @@ export class PageBuilderService {
1270
1310
  }
1271
1311
  }
1272
1312
 
1273
- async #hasLocalDraftForUpdate(): Promise<boolean> {
1313
+ async hasLocalDraftForUpdate(): Promise<boolean> {
1314
+ const pagebuilder = document.querySelector('#pagebuilder')
1315
+ if (!pagebuilder) {
1316
+ return true
1317
+ }
1318
+
1274
1319
  if (this.hasStartedEditing) return false
1275
1320
 
1276
1321
  if (
@@ -1285,11 +1330,8 @@ export class PageBuilderService {
1285
1330
  if (draft) {
1286
1331
  try {
1287
1332
  await this.delay(500)
1288
-
1333
+ this.pageBuilderStateStore.setHasLocalDraftForUpdate(false)
1289
1334
  return true
1290
- // const dbComponents = this.getComponents.value
1291
- // const draftParsed = JSON.parse(draft)
1292
- // return JSON.stringify(draftParsed.components) !== JSON.stringify(dbComponents)
1293
1335
  } catch (err) {
1294
1336
  console.error('Unable to mount components to DOM.', err)
1295
1337
  return false
@@ -1319,10 +1361,10 @@ export class PageBuilderService {
1319
1361
  const updateDraftFromLocalStorage = localStorage.getItem(key)
1320
1362
 
1321
1363
  if (typeof updateDraftFromLocalStorage === 'string') {
1322
- this.pageBuilderStateStore.setIsResumeEditing(true)
1364
+ this.pageBuilderStateStore.setIsLoadingResumeEditing(true)
1323
1365
  await delay(500)
1324
1366
  this.mountComponentsToDOM(updateDraftFromLocalStorage)
1325
- this.pageBuilderStateStore.setIsResumeEditing(false)
1367
+ this.pageBuilderStateStore.setIsLoadingResumeEditing(false)
1326
1368
  }
1327
1369
  }
1328
1370
  }
@@ -1355,6 +1397,7 @@ export class PageBuilderService {
1355
1397
  getStorageItemNameForResource(): string | null {
1356
1398
  return this.getLocalStorageItemName.value
1357
1399
  }
1400
+
1358
1401
  loadStoredComponentsFromStorage() {
1359
1402
  if (!this.getLocalStorageItemName.value) return false
1360
1403
 
@@ -1858,6 +1901,7 @@ export class PageBuilderService {
1858
1901
  if (this.pendingMountData && document.querySelector('#pagebuilder')) {
1859
1902
  await this.mountComponentsToDOM(this.pendingMountData)
1860
1903
  this.pendingMountData = null
1904
+ this.completeBuilderInitialization()
1861
1905
  }
1862
1906
  }
1863
1907
 
@@ -277,7 +277,7 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
277
277
  getIsLoadingGlobal: (state: PageBuilderState): boolean => state.isLoadingGlobal,
278
278
  getIsSaving: (state: PageBuilderState): boolean => state.isSaving,
279
279
  getHasLocalDraftForUpdate: (state: PageBuilderState): boolean => state.hasLocalDraftForUpdate,
280
- getIsResumeEditing: (state: PageBuilderState): boolean => state.isResumeEditing,
280
+ getIsLoadingResumeEditing: (state: PageBuilderState): boolean => state.isResumeEditing,
281
281
  getIsRestoring: (state: PageBuilderState): boolean => state.isRestoring,
282
282
  },
283
283
  actions: {
@@ -475,7 +475,7 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
475
475
  setHasLocalDraftForUpdate(payload: boolean): void {
476
476
  this.hasLocalDraftForUpdate = payload
477
477
  },
478
- setIsResumeEditing(payload: boolean): void {
478
+ setIsLoadingResumeEditing(payload: boolean): void {
479
479
  this.isResumeEditing = payload
480
480
  },
481
481
  setIsRestoring(payload: boolean): void {