@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/README.md +97 -355
- package/dist/vue-website-page-builder.js +896 -874
- package/dist/vue-website-page-builder.umd.cjs +31 -31
- package/package.json +1 -1
- package/src/Components/PageBuilder/EditorMenu/EditorAccordion.vue +1 -1
- package/src/DemoComponents/HomeSection.vue +2 -5
- package/src/PageBuilder/PageBuilder.vue +3 -9
- package/src/composables/PageBuilderService.ts +91 -22
package/package.json
CHANGED
|
@@ -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
|
-
|
|
267
|
-
if (pageBuilderService.statuspendingMountData()) {
|
|
268
|
-
await pageBuilderService.tryMountPendingData()
|
|
269
|
-
}
|
|
263
|
+
await pageBuilderService.tryMountPendingData()
|
|
270
264
|
|
|
271
265
|
// Check if Builder started
|
|
272
|
-
await delay(
|
|
266
|
+
await delay(10000)
|
|
273
267
|
ensureBuilderInitialized()
|
|
274
268
|
|
|
275
269
|
// Re-check if Builder started
|
|
276
|
-
await delay(
|
|
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
|
-
*
|
|
199
|
-
*
|
|
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
|
|
217
|
-
}
|
|
226
|
+
this.completeBuilderInitialization()
|
|
218
227
|
|
|
219
|
-
|
|
220
|
-
|
|
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
|
-
*
|
|
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:
|
|
1184
|
-
id:
|
|
1185
|
-
title:
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|