@myissue/vue-website-page-builder 3.2.90 → 3.2.92
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 +122 -84
- package/dist/vue-website-page-builder.css +1 -1
- package/dist/vue-website-page-builder.js +5191 -5273
- package/dist/vue-website-page-builder.umd.cjs +52 -52
- package/package.json +1 -1
- package/src/Components/Loaders/GlobalLoader.vue +11 -0
- package/src/Components/Modals/DynamicModalBuilder.vue +41 -245
- package/src/Components/Modals/ModalBuilder.vue +29 -4
- package/src/Components/PageBuilder/DefaultComponents/DefaultBuilderComponents.vue +3 -8
- package/src/Components/PageBuilder/EditorMenu/Editables/BackgroundColorEditor.vue +5 -4
- package/src/Components/PageBuilder/EditorMenu/Editables/BorderRadius.vue +12 -13
- package/src/Components/PageBuilder/EditorMenu/Editables/Borders.vue +8 -8
- package/src/Components/PageBuilder/EditorMenu/Editables/ClassEditor.vue +7 -6
- package/src/Components/PageBuilder/EditorMenu/Editables/ComponentTopMenu.vue +6 -10
- package/src/Components/PageBuilder/EditorMenu/Editables/DeleteElement.vue +4 -4
- package/src/Components/PageBuilder/EditorMenu/Editables/EditGetElement.vue +10 -11
- package/src/Components/PageBuilder/EditorMenu/Editables/ElementEditor.vue +4 -5
- package/src/Components/PageBuilder/EditorMenu/Editables/ImageEditor.vue +0 -9
- package/src/Components/PageBuilder/EditorMenu/Editables/LinkEditor.vue +5 -5
- package/src/Components/PageBuilder/EditorMenu/Editables/ManageBackgroundOpacity.vue +4 -4
- package/src/Components/PageBuilder/EditorMenu/Editables/ManageOpacity.vue +4 -4
- package/src/Components/PageBuilder/EditorMenu/Editables/Margin.vue +8 -8
- package/src/Components/PageBuilder/EditorMenu/Editables/Padding.vue +8 -8
- package/src/Components/PageBuilder/EditorMenu/Editables/TextColorEditor.vue +4 -4
- package/src/Components/PageBuilder/EditorMenu/Editables/Typography.vue +16 -16
- package/src/Components/PageBuilder/EditorMenu/RightSidebarEditor.vue +3 -7
- package/src/Components/PageBuilder/Settings/PageBuilderSettings.vue +55 -58
- package/src/Components/PageBuilder/ToolbarOption/ToolbarOption.vue +33 -40
- package/src/Components/TipTap/TipTap.vue +4 -9
- package/src/Components/TipTap/TipTapInput.vue +8 -8
- package/src/DemoComponents/DemoUnsplash.vue +4 -5
- package/src/DemoComponents/HomeSection.vue +9 -30
- package/src/DemoComponents/html.json +4 -4
- package/src/PageBuilder/PageBuilder.vue +194 -96
- package/src/composables/{PageBuilderClass.ts → PageBuilderService.ts} +258 -97
- package/src/composables/builderInstance.ts +25 -0
- package/src/css/app.css +15 -0
- package/src/css/dev-global.css +7 -0
- package/src/index.ts +4 -2
- package/src/main.ts +3 -0
- package/src/stores/page-builder-state.ts +32 -2
- package/src/types/index.ts +99 -9
- package/src/helpers/passedPageBuilderConfig.ts +0 -71
|
@@ -14,8 +14,9 @@ import { computed, ref, nextTick } from 'vue'
|
|
|
14
14
|
import type { ComputedRef } from 'vue'
|
|
15
15
|
import { v4 as uuidv4 } from 'uuid'
|
|
16
16
|
import { delay } from './delay'
|
|
17
|
+
import { isEmptyObject } from '../helpers/isEmptyObject'
|
|
17
18
|
|
|
18
|
-
class
|
|
19
|
+
export class PageBuilderService {
|
|
19
20
|
// Class properties with types
|
|
20
21
|
private nextTick: Promise<void>
|
|
21
22
|
private containsPagebuilder: Element | null
|
|
@@ -35,10 +36,10 @@ class PageBuilderClass {
|
|
|
35
36
|
private NoneListernesTags: string[]
|
|
36
37
|
private delay: (ms?: number) => Promise<void>
|
|
37
38
|
private hasStartedEditing: boolean = false
|
|
39
|
+
private originalComponents: string | null = null
|
|
38
40
|
|
|
39
41
|
constructor(pageBuilderStateStore: ReturnType<typeof usePageBuilderStateStore>) {
|
|
40
42
|
this.nextTick = nextTick()
|
|
41
|
-
|
|
42
43
|
this.hasStartedEditing = false
|
|
43
44
|
this.containsPagebuilder = document.querySelector('#contains-pagebuilder')
|
|
44
45
|
this.pageBuilderStateStore = pageBuilderStateStore
|
|
@@ -93,9 +94,138 @@ class PageBuilderClass {
|
|
|
93
94
|
this.pageBuilderStateStore.setElement(null)
|
|
94
95
|
await this.#removeHoveredAndSelected()
|
|
95
96
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
|
|
98
|
+
#ensureUpdateOrCreateConfig(config: PageBuilderConfig): void {
|
|
99
|
+
// Case A: updateOrCreate is missing or an empty object
|
|
100
|
+
if (!config.updateOrCreate || (config.updateOrCreate && isEmptyObject(config.updateOrCreate))) {
|
|
101
|
+
const updatedConfig = {
|
|
102
|
+
...config,
|
|
103
|
+
updateOrCreate: {
|
|
104
|
+
formType: 'create',
|
|
105
|
+
formName: 'post',
|
|
106
|
+
},
|
|
107
|
+
} as const
|
|
108
|
+
|
|
109
|
+
this.pageBuilderStateStore.setPageBuilderConfig(updatedConfig)
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Case B: formType is valid ('create' or 'update'), but formName is missing or an empty string
|
|
114
|
+
if (
|
|
115
|
+
(config.updateOrCreate &&
|
|
116
|
+
typeof config.updateOrCreate.formType === 'string' &&
|
|
117
|
+
(config.updateOrCreate.formType === 'create' ||
|
|
118
|
+
config.updateOrCreate.formType === 'update') &&
|
|
119
|
+
typeof config.updateOrCreate.formName !== 'string') ||
|
|
120
|
+
(typeof config.updateOrCreate.formName === 'string' &&
|
|
121
|
+
config.updateOrCreate.formName.length === 0)
|
|
122
|
+
) {
|
|
123
|
+
const updatedConfig = {
|
|
124
|
+
...config,
|
|
125
|
+
updateOrCreate: {
|
|
126
|
+
formType: config.updateOrCreate.formType,
|
|
127
|
+
formName: 'post',
|
|
128
|
+
},
|
|
129
|
+
} as const
|
|
130
|
+
this.pageBuilderStateStore.setPageBuilderConfig(updatedConfig)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Case C: formType is missing or not a valid string like ('create' or 'update') but formName is valid string
|
|
134
|
+
if (
|
|
135
|
+
(config.updateOrCreate && typeof config.updateOrCreate.formType !== 'string') ||
|
|
136
|
+
(typeof config.updateOrCreate.formType === 'string' &&
|
|
137
|
+
config.updateOrCreate.formType !== 'create' &&
|
|
138
|
+
config.updateOrCreate.formType !== 'update' &&
|
|
139
|
+
typeof config.updateOrCreate.formName === 'string' &&
|
|
140
|
+
config.updateOrCreate.formName.length !== 0)
|
|
141
|
+
) {
|
|
142
|
+
const updatedConfig = {
|
|
143
|
+
...config,
|
|
144
|
+
updateOrCreate: {
|
|
145
|
+
formType: 'create',
|
|
146
|
+
formName: config.updateOrCreate.formName,
|
|
147
|
+
},
|
|
148
|
+
} as const
|
|
149
|
+
|
|
150
|
+
this.pageBuilderStateStore.setPageBuilderConfig(updatedConfig)
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Case D: formType exists but is not 'create' or 'update', and formName is missing or invalid
|
|
155
|
+
if (
|
|
156
|
+
config.updateOrCreate &&
|
|
157
|
+
typeof config.updateOrCreate.formType === 'string' &&
|
|
158
|
+
config.updateOrCreate.formType !== 'create' &&
|
|
159
|
+
config.updateOrCreate.formType !== 'update' &&
|
|
160
|
+
typeof config.formName !== 'string'
|
|
161
|
+
) {
|
|
162
|
+
const updatedConfig = {
|
|
163
|
+
...config,
|
|
164
|
+
updateOrCreate: {
|
|
165
|
+
formType: 'create',
|
|
166
|
+
formName: 'post',
|
|
167
|
+
},
|
|
168
|
+
} as const
|
|
169
|
+
|
|
170
|
+
this.pageBuilderStateStore.setPageBuilderConfig(updatedConfig)
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
#validateConfig(config: PageBuilderConfig): void {
|
|
175
|
+
const defaultConfigValues = {
|
|
176
|
+
updateOrCreate: {
|
|
177
|
+
formType: 'create',
|
|
178
|
+
formName: 'post',
|
|
179
|
+
},
|
|
180
|
+
} as const
|
|
181
|
+
|
|
182
|
+
// Set config for page builder if not set by user
|
|
183
|
+
if (!config || (config && Object.keys(config).length === 0 && config.constructor === Object)) {
|
|
184
|
+
this.pageBuilderStateStore.setPageBuilderConfig(defaultConfigValues)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (config && Object.keys(config).length !== 0 && config.constructor === Object) {
|
|
188
|
+
this.#ensureUpdateOrCreateConfig(config)
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Initializes the Page Builder with the provided configuration.
|
|
194
|
+
* Handles config validation, local storage, and sets up the builder state.
|
|
195
|
+
*/
|
|
196
|
+
async startBuilder(config: PageBuilderConfig): Promise<void> {
|
|
197
|
+
// Show a global loading indicator while initializing
|
|
198
|
+
this.pageBuilderStateStore.setIsLoadingGlobal(true)
|
|
199
|
+
|
|
200
|
+
// Wait briefly to ensure UI updates and async processes settle
|
|
201
|
+
await this.delay(300)
|
|
202
|
+
|
|
203
|
+
// Store the provided config in the builder's state store
|
|
204
|
+
this.pageBuilderStateStore.setPageBuilderConfig(config)
|
|
205
|
+
|
|
206
|
+
// Validate and normalize the config (ensure required fields are present)
|
|
207
|
+
this.#validateConfig(config)
|
|
208
|
+
|
|
209
|
+
// Update the localStorage key name based on the config/resource
|
|
210
|
+
this.#updateLocalStorageItemName()
|
|
211
|
+
|
|
212
|
+
// If there is a local draft for this resource, mark it in the state
|
|
213
|
+
if (await this.#hasLocalDraftForUpdate()) {
|
|
214
|
+
this.pageBuilderStateStore.setHasLocalDraftForUpdate(true)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Clean up any old localStorage items related to previous builder sessions
|
|
218
|
+
this.deleteOldPageBuilderLocalStorage()
|
|
219
|
+
|
|
220
|
+
// Clear any selected HTML elements in the builder UI
|
|
221
|
+
await this.clearHtmlSelection()
|
|
222
|
+
|
|
223
|
+
// Attach event listeners to all editable elements in the builder
|
|
224
|
+
await this.addListenersToEditableElements()
|
|
225
|
+
|
|
226
|
+
// Hide the global loading indicator and mark the builder as started
|
|
227
|
+
this.pageBuilderStateStore.setIsLoadingGlobal(false)
|
|
228
|
+
this.pageBuilderStateStore.setBuilderStarted(true)
|
|
99
229
|
}
|
|
100
230
|
|
|
101
231
|
#applyElementClassChanges(
|
|
@@ -265,7 +395,7 @@ class PageBuilderClass {
|
|
|
265
395
|
|
|
266
396
|
handleAutoSave = async () => {
|
|
267
397
|
this.startEditing()
|
|
268
|
-
const passedConfig = this.pageBuilderStateStore.
|
|
398
|
+
const passedConfig = this.pageBuilderStateStore.getPageBuilderConfig
|
|
269
399
|
|
|
270
400
|
// Check if config is set
|
|
271
401
|
if (passedConfig && passedConfig.userSettings) {
|
|
@@ -280,7 +410,7 @@ class PageBuilderClass {
|
|
|
280
410
|
try {
|
|
281
411
|
this.pageBuilderStateStore.setIsSaving(true)
|
|
282
412
|
await this.saveComponentsLocalStorage()
|
|
283
|
-
await this.delay(
|
|
413
|
+
await this.delay(500)
|
|
284
414
|
} catch (err) {
|
|
285
415
|
console.error('Error trying auto save.', err)
|
|
286
416
|
} finally {
|
|
@@ -303,7 +433,7 @@ class PageBuilderClass {
|
|
|
303
433
|
|
|
304
434
|
handleManualSave = async () => {
|
|
305
435
|
this.startEditing()
|
|
306
|
-
const passedConfig = this.pageBuilderStateStore.
|
|
436
|
+
const passedConfig = this.pageBuilderStateStore.getPageBuilderConfig
|
|
307
437
|
|
|
308
438
|
// Check if config is set
|
|
309
439
|
if (passedConfig && passedConfig.userSettings) {
|
|
@@ -575,7 +705,6 @@ class PageBuilderClass {
|
|
|
575
705
|
)
|
|
576
706
|
}
|
|
577
707
|
|
|
578
|
-
// border color, style & width / start
|
|
579
708
|
handleBorderStyle(borderStyle?: string): void {
|
|
580
709
|
this.#applyElementClassChanges(
|
|
581
710
|
borderStyle,
|
|
@@ -611,7 +740,6 @@ class PageBuilderClass {
|
|
|
611
740
|
this.#applyElementClassChanges(color, tailwindColors.textColorVariables, 'setTextColor')
|
|
612
741
|
}
|
|
613
742
|
|
|
614
|
-
// border radius / start
|
|
615
743
|
handleBorderRadiusGlobal(borderRadiusGlobal?: string): void {
|
|
616
744
|
this.#applyElementClassChanges(
|
|
617
745
|
borderRadiusGlobal,
|
|
@@ -690,7 +818,7 @@ class PageBuilderClass {
|
|
|
690
818
|
this.pageBuilderStateStore.setComponents([])
|
|
691
819
|
}
|
|
692
820
|
|
|
693
|
-
deleteSelectedComponent() {
|
|
821
|
+
async deleteSelectedComponent() {
|
|
694
822
|
if (!this.getComponents.value || !this.getComponent.value) return
|
|
695
823
|
|
|
696
824
|
// Find the index of the component to delete
|
|
@@ -706,6 +834,8 @@ class PageBuilderClass {
|
|
|
706
834
|
// Remove the component from the array
|
|
707
835
|
this.getComponents.value.splice(indexToDelete, 1)
|
|
708
836
|
this.pageBuilderStateStore.setComponents(this.getComponents.value)
|
|
837
|
+
await nextTick()
|
|
838
|
+
await this.addListenersToEditableElements()
|
|
709
839
|
|
|
710
840
|
this.pageBuilderStateStore.setComponent(null)
|
|
711
841
|
this.pageBuilderStateStore.setElement(null)
|
|
@@ -879,16 +1009,16 @@ class PageBuilderClass {
|
|
|
879
1009
|
.replace(/^-+|-+$/g, '') // Remove leading/trailing hyphens
|
|
880
1010
|
}
|
|
881
1011
|
|
|
882
|
-
updateLocalStorageItemName(): void {
|
|
1012
|
+
#updateLocalStorageItemName(): void {
|
|
883
1013
|
const updateOrCreate =
|
|
884
|
-
this.pageBuilderStateStore.
|
|
885
|
-
this.pageBuilderStateStore.
|
|
886
|
-
this.pageBuilderStateStore.
|
|
1014
|
+
this.pageBuilderStateStore.getPageBuilderConfig &&
|
|
1015
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
|
|
1016
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType
|
|
887
1017
|
|
|
888
|
-
const resourceData = this.pageBuilderStateStore.
|
|
1018
|
+
const resourceData = this.pageBuilderStateStore.getPageBuilderConfig?.resourceData
|
|
889
1019
|
|
|
890
1020
|
const resourceFormName =
|
|
891
|
-
this.pageBuilderStateStore.
|
|
1021
|
+
this.pageBuilderStateStore.getPageBuilderConfig?.updateOrCreate?.formName
|
|
892
1022
|
|
|
893
1023
|
// Logic for create resource
|
|
894
1024
|
if (updateOrCreate === 'create') {
|
|
@@ -906,9 +1036,6 @@ class PageBuilderClass {
|
|
|
906
1036
|
// Logic for create
|
|
907
1037
|
// Logic for update and with resource form name
|
|
908
1038
|
if (updateOrCreate === 'update') {
|
|
909
|
-
//
|
|
910
|
-
//
|
|
911
|
-
//
|
|
912
1039
|
if (typeof resourceFormName === 'string' && resourceFormName.length > 0) {
|
|
913
1040
|
//
|
|
914
1041
|
//
|
|
@@ -1053,14 +1180,16 @@ class PageBuilderClass {
|
|
|
1053
1180
|
})
|
|
1054
1181
|
})
|
|
1055
1182
|
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1183
|
+
// Save to localStorage with pageBuilderContentSavedAt using the correct key
|
|
1184
|
+
const dataToSave = {
|
|
1185
|
+
components: componentsToSave,
|
|
1186
|
+
pageBuilderContentSavedAt: new Date().toISOString(),
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
const keyForSavingFromDomToLocal = this.getLocalStorageItemName.value
|
|
1190
|
+
|
|
1191
|
+
if (keyForSavingFromDomToLocal && typeof keyForSavingFromDomToLocal === 'string') {
|
|
1192
|
+
localStorage.setItem(keyForSavingFromDomToLocal, JSON.stringify(dataToSave))
|
|
1064
1193
|
}
|
|
1065
1194
|
|
|
1066
1195
|
// No DOM mutation here!
|
|
@@ -1085,10 +1214,10 @@ class PageBuilderClass {
|
|
|
1085
1214
|
//
|
|
1086
1215
|
deleteOldPageBuilderLocalStorage(): void {
|
|
1087
1216
|
if (
|
|
1088
|
-
this.pageBuilderStateStore.
|
|
1089
|
-
this.pageBuilderStateStore.
|
|
1090
|
-
typeof this.pageBuilderStateStore.
|
|
1091
|
-
this.pageBuilderStateStore.
|
|
1217
|
+
this.pageBuilderStateStore.getPageBuilderConfig &&
|
|
1218
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
|
|
1219
|
+
typeof this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'string' &&
|
|
1220
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'update'
|
|
1092
1221
|
) {
|
|
1093
1222
|
let oldCountLocalStorages = 0
|
|
1094
1223
|
const deletedItemsLog: { Number: number; Key: string; SavedAt: string }[] = []
|
|
@@ -1137,14 +1266,14 @@ class PageBuilderClass {
|
|
|
1137
1266
|
}
|
|
1138
1267
|
}
|
|
1139
1268
|
|
|
1140
|
-
async hasLocalDraftForUpdate(): Promise<boolean> {
|
|
1269
|
+
async #hasLocalDraftForUpdate(): Promise<boolean> {
|
|
1141
1270
|
if (this.hasStartedEditing) return false
|
|
1142
1271
|
|
|
1143
1272
|
if (
|
|
1144
|
-
this.pageBuilderStateStore.
|
|
1145
|
-
this.pageBuilderStateStore.
|
|
1146
|
-
typeof this.pageBuilderStateStore.
|
|
1147
|
-
this.pageBuilderStateStore.
|
|
1273
|
+
this.pageBuilderStateStore.getPageBuilderConfig &&
|
|
1274
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
|
|
1275
|
+
typeof this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'string' &&
|
|
1276
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'update'
|
|
1148
1277
|
) {
|
|
1149
1278
|
const key = this.getLocalStorageItemName.value
|
|
1150
1279
|
if (typeof key === 'string') {
|
|
@@ -1152,10 +1281,13 @@ class PageBuilderClass {
|
|
|
1152
1281
|
if (draft) {
|
|
1153
1282
|
try {
|
|
1154
1283
|
await this.delay(500)
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1284
|
+
|
|
1285
|
+
return true
|
|
1286
|
+
// const dbComponents = this.getComponents.value
|
|
1287
|
+
// const draftParsed = JSON.parse(draft)
|
|
1288
|
+
// return JSON.stringify(draftParsed.components) !== JSON.stringify(dbComponents)
|
|
1289
|
+
} catch (err) {
|
|
1290
|
+
console.error('Unable to mount components to DOM.', err)
|
|
1159
1291
|
return false
|
|
1160
1292
|
}
|
|
1161
1293
|
}
|
|
@@ -1169,34 +1301,51 @@ class PageBuilderClass {
|
|
|
1169
1301
|
this.hasStartedEditing = true
|
|
1170
1302
|
}
|
|
1171
1303
|
|
|
1304
|
+
//
|
|
1172
1305
|
async resumeEditingForUpdate() {
|
|
1173
1306
|
if (
|
|
1174
|
-
this.pageBuilderStateStore.
|
|
1175
|
-
this.pageBuilderStateStore.
|
|
1176
|
-
typeof this.pageBuilderStateStore.
|
|
1177
|
-
this.pageBuilderStateStore.
|
|
1307
|
+
this.pageBuilderStateStore.getPageBuilderConfig &&
|
|
1308
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
|
|
1309
|
+
typeof this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'string' &&
|
|
1310
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'update'
|
|
1178
1311
|
) {
|
|
1179
1312
|
const key = this.getLocalStorageItemName.value
|
|
1313
|
+
|
|
1180
1314
|
if (typeof key === 'string') {
|
|
1181
|
-
const
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
await nextTick()
|
|
1189
|
-
await this.addListenersToEditableElements()
|
|
1190
|
-
await this.handleAutoSave()
|
|
1191
|
-
}
|
|
1192
|
-
} catch (e) {
|
|
1193
|
-
console.error('Failed to parse local draft:', e)
|
|
1194
|
-
}
|
|
1315
|
+
const updateDraftFromLocalStorage = localStorage.getItem(key)
|
|
1316
|
+
|
|
1317
|
+
if (typeof updateDraftFromLocalStorage === 'string') {
|
|
1318
|
+
this.pageBuilderStateStore.setIsResumeEditing(true)
|
|
1319
|
+
await delay(500)
|
|
1320
|
+
this.mountComponentsToDOM(updateDraftFromLocalStorage)
|
|
1321
|
+
this.pageBuilderStateStore.setIsResumeEditing(false)
|
|
1195
1322
|
}
|
|
1196
1323
|
}
|
|
1197
1324
|
}
|
|
1198
1325
|
}
|
|
1199
1326
|
|
|
1327
|
+
async restoreOriginalContent() {
|
|
1328
|
+
if (
|
|
1329
|
+
this.pageBuilderStateStore.getPageBuilderConfig &&
|
|
1330
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
|
|
1331
|
+
typeof this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'string' &&
|
|
1332
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'update'
|
|
1333
|
+
) {
|
|
1334
|
+
this.pageBuilderStateStore.setIsRestoring(true)
|
|
1335
|
+
await this.delay(300)
|
|
1336
|
+
|
|
1337
|
+
// Restore the original content if available
|
|
1338
|
+
if (this.originalComponents) {
|
|
1339
|
+
this.mountComponentsToDOM(this.originalComponents)
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
await nextTick()
|
|
1343
|
+
await this.addListenersToEditableElements()
|
|
1344
|
+
|
|
1345
|
+
this.pageBuilderStateStore.setIsRestoring(false)
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1200
1349
|
getStorageItemNameForResource(): string | null {
|
|
1201
1350
|
return this.getLocalStorageItemName.value
|
|
1202
1351
|
}
|
|
@@ -1476,9 +1625,9 @@ class PageBuilderClass {
|
|
|
1476
1625
|
* @param data - JSON string (e.g., '[{"html_code":"...","id":"123","title":"..."}]')
|
|
1477
1626
|
* OR HTML string (e.g., '<section data-componentid="123">...</section>')
|
|
1478
1627
|
*/
|
|
1479
|
-
setComponentsFromData(
|
|
1628
|
+
#setComponentsFromData(htmlString: string): void {
|
|
1480
1629
|
// Auto-detect if input is JSON or HTML
|
|
1481
|
-
const trimmedData =
|
|
1630
|
+
const trimmedData = htmlString.trim()
|
|
1482
1631
|
|
|
1483
1632
|
if (trimmedData.startsWith('[') || trimmedData.startsWith('{')) {
|
|
1484
1633
|
// Looks like JSON - parse as JSON
|
|
@@ -1492,7 +1641,7 @@ class PageBuilderClass {
|
|
|
1492
1641
|
}
|
|
1493
1642
|
|
|
1494
1643
|
// Private method to parse JSON components and save pageBuilderContentSavedAt to localStorage
|
|
1495
|
-
#parseJSONComponents(jsonData: string): void {
|
|
1644
|
+
async #parseJSONComponents(jsonData: string): Promise<void> {
|
|
1496
1645
|
try {
|
|
1497
1646
|
const parsedData = JSON.parse(jsonData)
|
|
1498
1647
|
let componentsArray: ComponentObject[] = []
|
|
@@ -1544,18 +1693,8 @@ class PageBuilderClass {
|
|
|
1544
1693
|
|
|
1545
1694
|
this.pageBuilderStateStore.setComponents(savedCurrentDesign)
|
|
1546
1695
|
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
pageBuilderContentSavedAt: parsedData.pageBuilderContentSavedAt || new Date().toISOString(),
|
|
1550
|
-
components: savedCurrentDesign,
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
|
-
if (
|
|
1554
|
-
this.getLocalStorageItemName.value &&
|
|
1555
|
-
typeof this.getLocalStorageItemName.value === 'string'
|
|
1556
|
-
) {
|
|
1557
|
-
localStorage.setItem(this.getLocalStorageItemName.value, JSON.stringify(dataToSave))
|
|
1558
|
-
}
|
|
1696
|
+
await this.clearHtmlSelection()
|
|
1697
|
+
await this.addListenersToEditableElements()
|
|
1559
1698
|
} catch (error) {
|
|
1560
1699
|
console.error('Error parsing JSON components:', error)
|
|
1561
1700
|
this.pageBuilderStateStore.setComponents([])
|
|
@@ -1602,37 +1741,60 @@ class PageBuilderClass {
|
|
|
1602
1741
|
}
|
|
1603
1742
|
}
|
|
1604
1743
|
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1744
|
+
/**
|
|
1745
|
+
* Mount Components to DOM
|
|
1746
|
+
* @param passedData - HTML/JSON string to inject (optional)
|
|
1747
|
+
* @param preferLocalStorage - if true, always try localStorage first
|
|
1748
|
+
*/
|
|
1749
|
+
mountComponentsToDOM(passedData: string): void {
|
|
1750
|
+
// Save the original content only once, in update mode, and only if passedData is provided
|
|
1751
|
+
// Form type Update
|
|
1752
|
+
if (
|
|
1753
|
+
this.pageBuilderStateStore.getPageBuilderConfig &&
|
|
1754
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
|
|
1755
|
+
typeof this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'string' &&
|
|
1756
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'update' &&
|
|
1757
|
+
passedData &&
|
|
1758
|
+
!this.originalComponents
|
|
1759
|
+
) {
|
|
1760
|
+
this.originalComponents = passedData
|
|
1613
1761
|
}
|
|
1614
1762
|
|
|
1615
|
-
|
|
1763
|
+
this.pageBuilderStateStore.setComponents([])
|
|
1764
|
+
|
|
1765
|
+
if (!this.pageBuilderStateStore.getPageBuilderConfig) return
|
|
1616
1766
|
|
|
1767
|
+
// Form type Update
|
|
1617
1768
|
if (
|
|
1618
|
-
this.pageBuilderStateStore.
|
|
1619
|
-
this.pageBuilderStateStore.
|
|
1620
|
-
typeof this.pageBuilderStateStore.
|
|
1621
|
-
this.pageBuilderStateStore.
|
|
1769
|
+
this.pageBuilderStateStore.getPageBuilderConfig &&
|
|
1770
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
|
|
1771
|
+
typeof this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'string' &&
|
|
1772
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'update'
|
|
1622
1773
|
) {
|
|
1623
|
-
if (
|
|
1624
|
-
this
|
|
1774
|
+
if (passedData) {
|
|
1775
|
+
this.#setComponentsFromData(passedData)
|
|
1776
|
+
return
|
|
1625
1777
|
}
|
|
1626
1778
|
}
|
|
1627
1779
|
|
|
1780
|
+
// Form type Create
|
|
1781
|
+
const localStorageData = this.loadStoredComponentsFromStorage()
|
|
1782
|
+
|
|
1628
1783
|
if (
|
|
1629
|
-
this.pageBuilderStateStore.
|
|
1630
|
-
this.pageBuilderStateStore.
|
|
1631
|
-
typeof this.pageBuilderStateStore.
|
|
1632
|
-
this.pageBuilderStateStore.
|
|
1784
|
+
this.pageBuilderStateStore.getPageBuilderConfig &&
|
|
1785
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate &&
|
|
1786
|
+
typeof this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'string' &&
|
|
1787
|
+
this.pageBuilderStateStore.getPageBuilderConfig.updateOrCreate.formType === 'create'
|
|
1633
1788
|
) {
|
|
1634
|
-
if (
|
|
1635
|
-
this
|
|
1789
|
+
if (localStorageData) {
|
|
1790
|
+
this.#setComponentsFromData(localStorageData)
|
|
1791
|
+
return
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
// If no localStorage, but passedData exists (for demo), use it
|
|
1795
|
+
if (passedData) {
|
|
1796
|
+
this.#setComponentsFromData(passedData)
|
|
1797
|
+
return
|
|
1636
1798
|
}
|
|
1637
1799
|
}
|
|
1638
1800
|
}
|
|
@@ -1646,6 +1808,7 @@ class PageBuilderClass {
|
|
|
1646
1808
|
}
|
|
1647
1809
|
|
|
1648
1810
|
async initializeElementStyles(): Promise<void> {
|
|
1811
|
+
if (!this.pageBuilderStateStore.getPageBuilderConfig) return
|
|
1649
1812
|
await new Promise((resolve) => requestAnimationFrame(resolve))
|
|
1650
1813
|
|
|
1651
1814
|
// handle custom URL
|
|
@@ -1699,5 +1862,3 @@ class PageBuilderClass {
|
|
|
1699
1862
|
await this.#syncCurrentClasses()
|
|
1700
1863
|
}
|
|
1701
1864
|
}
|
|
1702
|
-
|
|
1703
|
-
export default PageBuilderClass
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// builderInstance.ts
|
|
2
|
+
import { PageBuilderService } from '../composables/PageBuilderService'
|
|
3
|
+
import { sharedPageBuilderStore } from '../stores/shared-store'
|
|
4
|
+
|
|
5
|
+
// Singleton instance
|
|
6
|
+
let instance: PageBuilderService | null = null
|
|
7
|
+
|
|
8
|
+
// Used to create and store the single instance
|
|
9
|
+
export function initPageBuilder(): PageBuilderService {
|
|
10
|
+
if (!instance) {
|
|
11
|
+
const pageBuilderStateStore = sharedPageBuilderStore
|
|
12
|
+
instance = new PageBuilderService(pageBuilderStateStore)
|
|
13
|
+
}
|
|
14
|
+
return instance
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Used to access the existing instance anywhere else
|
|
18
|
+
export function getPageBuilder(): PageBuilderService {
|
|
19
|
+
if (!instance) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
'PageBuilderService has not been created. Please call createPageBuilder() first in your App.vue or setup file.',
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
return instance
|
|
25
|
+
}
|
package/src/css/app.css
CHANGED
|
@@ -357,3 +357,18 @@
|
|
|
357
357
|
@apply pbx-aspect-square pbx-border pbx-border-gray-200 pbx-cursor-pointer pbx-min-h-[1.5rem] pbx-rounded-sm;
|
|
358
358
|
}
|
|
359
359
|
}
|
|
360
|
+
|
|
361
|
+
/* p {
|
|
362
|
+
@apply pbx-font-normal lg:pbx-text-base pbx-text-base;
|
|
363
|
+
} */
|
|
364
|
+
|
|
365
|
+
a {
|
|
366
|
+
@apply pbx-text-myPrimaryLinkColor;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
h2 {
|
|
370
|
+
@apply pbx-text-3xl pbx-mt-4 pbx-mb-3 pbx-font-medium;
|
|
371
|
+
}
|
|
372
|
+
h3 {
|
|
373
|
+
@apply pbx-text-2xl pbx-mt-4 pbx-mb-3 pbx-font-medium;
|
|
374
|
+
}
|
package/src/css/dev-global.css
CHANGED
|
@@ -14,8 +14,15 @@ These styles affect all HTML elements (like input, button, h1, etc.) in the cons
|
|
|
14
14
|
}
|
|
15
15
|
/* CSS for content inside page builder # start */
|
|
16
16
|
#page-builder-editor .tiptap {
|
|
17
|
+
outline: none !important;
|
|
18
|
+
box-shadow: none !important;
|
|
17
19
|
background: #fff;
|
|
18
20
|
min-height: 25rem;
|
|
21
|
+
border: 1px solid #aaa;
|
|
22
|
+
border-radius: 10px;
|
|
23
|
+
padding: 6px;
|
|
24
|
+
margin-bottom: 20px;
|
|
25
|
+
padding-bottom: 100px;
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
#pagebuilder #youtube-video::before {
|
package/src/index.ts
CHANGED
|
@@ -5,8 +5,6 @@ export { default as Preview } from './PageBuilder/Preview.vue'
|
|
|
5
5
|
// Export stores (consolidated into single store)
|
|
6
6
|
export { usePageBuilderStateStore } from './stores/page-builder-state'
|
|
7
7
|
|
|
8
|
-
export { default as PageBuilderClass } from './composables/PageBuilderClass.ts'
|
|
9
|
-
|
|
10
8
|
// Export composables
|
|
11
9
|
export { usePageBuilderModal } from './composables/usePageBuilderModal'
|
|
12
10
|
|
|
@@ -21,3 +19,7 @@ import './css/app.css'
|
|
|
21
19
|
|
|
22
20
|
// Export shared store instances for external access
|
|
23
21
|
export { sharedPageBuilderPinia, sharedPageBuilderStore } from './stores/shared-store'
|
|
22
|
+
|
|
23
|
+
// export { PageBuilderService } from './composables/PageBuilderService.ts'
|
|
24
|
+
|
|
25
|
+
export { initPageBuilder, getPageBuilder } from './composables/builderInstance'
|
package/src/main.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import './css/dev-global.css'
|
|
2
2
|
import './css/app.css'
|
|
3
|
+
import { initPageBuilder } from './composables/builderInstance'
|
|
3
4
|
|
|
4
5
|
import { createApp } from 'vue'
|
|
5
6
|
import { createPinia } from 'pinia'
|
|
6
7
|
import App from './App.vue'
|
|
7
8
|
|
|
9
|
+
initPageBuilder()
|
|
10
|
+
|
|
8
11
|
const app = createApp(App)
|
|
9
12
|
|
|
10
13
|
app.use(createPinia())
|