@myissue/vue-website-page-builder 3.1.13 → 3.1.15
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/dist/vue-website-page-builder.css +1 -1
- package/dist/vue-website-page-builder.js +5161 -5194
- package/dist/vue-website-page-builder.umd.cjs +38 -38
- package/package.json +1 -1
- package/src/App.vue +2 -2
- package/src/Components/Homepage/HomeSection.vue +18 -7
- package/src/Components/Modals/{DynamicModal.vue → DynamicModalBuilder.vue} +38 -31
- package/src/Components/Modals/MediaLibraryModal.vue +1 -1
- package/src/Components/Modals/{Modal.vue → ModalBuilder.vue} +9 -15
- package/src/Components/Modals/PageBuilderPreviewModal.vue +13 -6
- package/src/Components/PageBuilder/DemoContent/NoneCustomSearchComponent.vue +0 -17
- package/src/Components/PageBuilder/DropdownsPlusToggles/OptionsDropdown.vue +113 -87
- package/src/Components/PageBuilder/EditorMenu/Editables/BackgroundColorEditor.vue +2 -2
- package/src/Components/PageBuilder/EditorMenu/Editables/BorderRadius.vue +2 -2
- package/src/Components/PageBuilder/EditorMenu/Editables/Borders.vue +3 -3
- package/src/Components/PageBuilder/EditorMenu/Editables/ClassEditor.vue +1 -1
- package/src/Components/PageBuilder/EditorMenu/Editables/ComponentTopMenu.vue +13 -13
- package/src/Components/PageBuilder/EditorMenu/Editables/DeleteElement.vue +1 -1
- package/src/Components/PageBuilder/EditorMenu/Editables/EditGetElement.vue +25 -25
- package/src/Components/PageBuilder/EditorMenu/Editables/ElementEditor.vue +2 -2
- package/src/Components/PageBuilder/EditorMenu/Editables/ImageEditor.vue +3 -3
- package/src/Components/PageBuilder/EditorMenu/Editables/LinkEditor.vue +1 -1
- package/src/Components/PageBuilder/EditorMenu/Editables/ManageBackgroundOpacity.vue +2 -2
- package/src/Components/PageBuilder/EditorMenu/Editables/ManageOpacity.vue +2 -2
- package/src/Components/PageBuilder/EditorMenu/Editables/OpacityEditor.vue +3 -3
- package/src/Components/PageBuilder/EditorMenu/Editables/PaddingPlusMargin.vue +2 -2
- package/src/Components/PageBuilder/EditorMenu/Editables/TextColorEditor.vue +2 -2
- package/src/Components/PageBuilder/EditorMenu/Editables/Typography.vue +3 -3
- package/src/Components/PageBuilder/EditorMenu/RightSidebarEditor.vue +13 -13
- package/src/Components/PageBuilder/Settings/AdvancedPageBuilderSettings.vue +9 -1
- package/src/Components/PageBuilder/Settings/PageBuilderSettings.vue +306 -15
- package/src/Components/Search/SearchComponents.vue +14 -8
- package/src/Components/TipTap/TipTap.vue +1 -1
- package/src/Components/TipTap/TipTapInput.vue +15 -17
- package/src/PageBuilder/PageBuilder.vue +37 -131
- package/src/composables/PageBuilderClass.ts +90 -80
- package/src/stores/page-builder-state.ts +9 -192
- package/src/types/index.ts +13 -10
- package/src/utils/builder/html-doc-declaration-with-components.ts +1 -1
- package/src/utils/html-elements/componentHelpers.ts +3 -3
- package/src/composables/isObject.ts +0 -6
- package/src/composables/usePromise.ts +0 -10
- package/src/composables/vueFetch.ts +0 -278
|
@@ -1,35 +1,14 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
2
|
import { nextTick } from 'vue'
|
|
3
|
-
import { vueFetch } from '@/composables/vueFetch'
|
|
4
3
|
import type {
|
|
5
4
|
ComponentObject,
|
|
6
|
-
FetchedComponentsResponse,
|
|
7
5
|
SetPushComponentsPayload,
|
|
8
|
-
LoadComponentsData,
|
|
9
6
|
ImageObject,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} from '@/types'
|
|
13
|
-
|
|
14
|
-
// Media Library interfaces
|
|
15
|
-
interface UnsplashImagesData {
|
|
16
|
-
fetchedMedia: unknown
|
|
17
|
-
isError: boolean | null
|
|
18
|
-
error: unknown
|
|
19
|
-
errors: unknown
|
|
20
|
-
isLoading: boolean | null
|
|
21
|
-
isSuccess: boolean | null
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface LoadUnsplashImagesPayload {
|
|
25
|
-
orientation?: string
|
|
26
|
-
currentPage: number
|
|
27
|
-
searchTerm?: string
|
|
28
|
-
}
|
|
7
|
+
PageBuilderConfig,
|
|
8
|
+
} from '../types'
|
|
29
9
|
|
|
30
10
|
interface PageBuilderState {
|
|
31
11
|
// Core Page Builder State
|
|
32
|
-
pageBuilderLogo: string | null
|
|
33
12
|
componentArrayAddMethod: string | null
|
|
34
13
|
localStorageItemName: string | null
|
|
35
14
|
showModalTipTap: boolean
|
|
@@ -73,9 +52,7 @@ interface PageBuilderState {
|
|
|
73
52
|
component: ComponentObject | null
|
|
74
53
|
components: ComponentObject[]
|
|
75
54
|
basePrimaryImage: string | null
|
|
76
|
-
|
|
77
|
-
currentResourceData: { title: string; id: number } | null
|
|
78
|
-
updateOrCreate: string
|
|
55
|
+
configPageBuilder: PageBuilderConfig | null
|
|
79
56
|
|
|
80
57
|
// Media Library State
|
|
81
58
|
currentImage: ImageObject
|
|
@@ -83,40 +60,11 @@ interface PageBuilderState {
|
|
|
83
60
|
|
|
84
61
|
// User State
|
|
85
62
|
isLoading: boolean
|
|
86
|
-
userSettings: UserSettings | null
|
|
87
|
-
currentUser: User | null
|
|
88
|
-
|
|
89
|
-
// Unsplash State
|
|
90
|
-
unsplashImages: UnsplashImagesData | null
|
|
91
|
-
searchTerm: string
|
|
92
|
-
currentPageNumber: number
|
|
93
|
-
orientationValue: string | null
|
|
94
63
|
}
|
|
95
64
|
|
|
96
|
-
// get components
|
|
97
|
-
const {
|
|
98
|
-
handleData: handlefetchComponents,
|
|
99
|
-
fetchedData: fetchedComponents,
|
|
100
|
-
isLoading,
|
|
101
|
-
isError,
|
|
102
|
-
error,
|
|
103
|
-
} = vueFetch()
|
|
104
|
-
|
|
105
|
-
// get unsplash images
|
|
106
|
-
const {
|
|
107
|
-
handleData: handleGetImages,
|
|
108
|
-
fetchedData: fetchedMedia,
|
|
109
|
-
isError: isErrorImages,
|
|
110
|
-
error: errorImages,
|
|
111
|
-
errors: errorsImages,
|
|
112
|
-
isLoading: isLoadingImages,
|
|
113
|
-
isSuccess: isSuccessImages,
|
|
114
|
-
} = vueFetch()
|
|
115
|
-
|
|
116
65
|
export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
117
66
|
state: (): PageBuilderState => ({
|
|
118
67
|
// Core Page Builder State
|
|
119
|
-
pageBuilderLogo: null,
|
|
120
68
|
componentArrayAddMethod: null,
|
|
121
69
|
localStorageItemName: null,
|
|
122
70
|
showModalTipTap: false,
|
|
@@ -160,9 +108,7 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
160
108
|
component: null,
|
|
161
109
|
components: [],
|
|
162
110
|
basePrimaryImage: null,
|
|
163
|
-
|
|
164
|
-
currentResourceData: null,
|
|
165
|
-
updateOrCreate: '',
|
|
111
|
+
configPageBuilder: null,
|
|
166
112
|
|
|
167
113
|
// Media Library State
|
|
168
114
|
currentImage: { src: '' },
|
|
@@ -170,20 +116,9 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
170
116
|
|
|
171
117
|
// User State
|
|
172
118
|
isLoading: false,
|
|
173
|
-
userSettings: null,
|
|
174
|
-
currentUser: null,
|
|
175
|
-
|
|
176
|
-
// Unsplash State
|
|
177
|
-
unsplashImages: null,
|
|
178
|
-
searchTerm: '',
|
|
179
|
-
currentPageNumber: 1,
|
|
180
|
-
orientationValue: null,
|
|
181
119
|
}),
|
|
182
120
|
getters: {
|
|
183
121
|
// Core Page Builder Getters
|
|
184
|
-
getPageBuilderLogo(state: PageBuilderState): string | null {
|
|
185
|
-
return state.pageBuilderLogo
|
|
186
|
-
},
|
|
187
122
|
getComponentArrayAddMethod(state: PageBuilderState): string | null {
|
|
188
123
|
return state.componentArrayAddMethod
|
|
189
124
|
},
|
|
@@ -313,27 +248,9 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
313
248
|
getBasePrimaryImage(state: PageBuilderState): string | null {
|
|
314
249
|
return state.basePrimaryImage
|
|
315
250
|
},
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
error: string | null
|
|
320
|
-
fetchedData: unknown
|
|
321
|
-
} {
|
|
322
|
-
return {
|
|
323
|
-
isLoading: isLoading.value,
|
|
324
|
-
isError: isError.value,
|
|
325
|
-
error: error.value,
|
|
326
|
-
fetchedData: fetchedComponents.value,
|
|
327
|
-
}
|
|
328
|
-
},
|
|
329
|
-
getFetchedComponentsData(state: PageBuilderState): FetchedComponentsResponse | null {
|
|
330
|
-
return state.fetchedComponents
|
|
331
|
-
},
|
|
332
|
-
getCurrentResourceData(state: PageBuilderState): { title: string; id: number } | null {
|
|
333
|
-
return state.currentResourceData
|
|
334
|
-
},
|
|
335
|
-
getUpdateOrCreate(state: PageBuilderState): string {
|
|
336
|
-
return state.updateOrCreate
|
|
251
|
+
|
|
252
|
+
getConfigPageBuilder(state: PageBuilderState): PageBuilderConfig | null {
|
|
253
|
+
return state.configPageBuilder
|
|
337
254
|
},
|
|
338
255
|
|
|
339
256
|
// Media Library Getters
|
|
@@ -346,22 +263,8 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
346
263
|
|
|
347
264
|
// User Getters
|
|
348
265
|
getIsLoading: (state: PageBuilderState): boolean => state.isLoading,
|
|
349
|
-
getUserSettings: (state: PageBuilderState): UserSettings | null => state.userSettings,
|
|
350
|
-
getCurrentUser: (state: PageBuilderState): User | null => state.currentUser,
|
|
351
|
-
|
|
352
|
-
// Unsplash Getters
|
|
353
|
-
getUnsplashImages: (state: PageBuilderState): UnsplashImagesData | null => {
|
|
354
|
-
return state.unsplashImages
|
|
355
|
-
},
|
|
356
|
-
getSearchTerm: (state: PageBuilderState): string => state.searchTerm,
|
|
357
|
-
getCurrentPageNumber: (state: PageBuilderState): number => state.currentPageNumber,
|
|
358
|
-
getOrientationValue: (state: PageBuilderState): string | null => state.orientationValue,
|
|
359
266
|
},
|
|
360
267
|
actions: {
|
|
361
|
-
// Core Page Builder Actions
|
|
362
|
-
setPageBuilderLogo(payload: string | null): void {
|
|
363
|
-
this.pageBuilderLogo = payload
|
|
364
|
-
},
|
|
365
268
|
setComponentArrayAddMethod(payload: string | null): void {
|
|
366
269
|
this.componentArrayAddMethod = payload
|
|
367
270
|
},
|
|
@@ -531,34 +434,9 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
531
434
|
setCurrentLayoutPreview(payload: string): void {
|
|
532
435
|
localStorage.setItem('preview', payload)
|
|
533
436
|
},
|
|
534
|
-
setFetchedComponents(payload: FetchedComponentsResponse | null): void {
|
|
535
|
-
this.fetchedComponents = payload
|
|
536
|
-
},
|
|
537
|
-
|
|
538
|
-
async setLoadComponents(_data: LoadComponentsData): Promise<void> {
|
|
539
|
-
this.setFetchedComponents(null)
|
|
540
437
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
} catch (err) {
|
|
544
|
-
console.log(`Error: ${err}`)
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
// fetchedComponents.value is an object containing a components property
|
|
548
|
-
this.setFetchedComponents(
|
|
549
|
-
fetchedComponents &&
|
|
550
|
-
fetchedComponents.value &&
|
|
551
|
-
typeof fetchedComponents.value === 'object' &&
|
|
552
|
-
'components' in fetchedComponents.value
|
|
553
|
-
? (fetchedComponents.value as FetchedComponentsResponse)
|
|
554
|
-
: null,
|
|
555
|
-
)
|
|
556
|
-
},
|
|
557
|
-
setCurrentResourceData(payload: { title: string; id: number } | null): void {
|
|
558
|
-
this.currentResourceData = payload
|
|
559
|
-
},
|
|
560
|
-
setUpdateOrCreate(payload: string): void {
|
|
561
|
-
this.updateOrCreate = payload
|
|
438
|
+
setConfigPageBuilder(payload: PageBuilderConfig | null): void {
|
|
439
|
+
this.configPageBuilder = payload
|
|
562
440
|
},
|
|
563
441
|
|
|
564
442
|
// Media Library Actions
|
|
@@ -573,66 +451,5 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
573
451
|
setIsLoading(payload: boolean): void {
|
|
574
452
|
this.isLoading = payload
|
|
575
453
|
},
|
|
576
|
-
setUserSettings(payload: UserSettings | null): void {
|
|
577
|
-
this.userSettings = payload
|
|
578
|
-
},
|
|
579
|
-
setCurrentUser(payload: User | null): void {
|
|
580
|
-
this.currentUser = payload
|
|
581
|
-
},
|
|
582
|
-
|
|
583
|
-
// Unsplash Actions
|
|
584
|
-
setUnsplashImages(payload: UnsplashImagesData | null): void {
|
|
585
|
-
this.unsplashImages = payload
|
|
586
|
-
},
|
|
587
|
-
setSearchTerm(payload: string): void {
|
|
588
|
-
this.searchTerm = payload
|
|
589
|
-
},
|
|
590
|
-
setCurrentPageNumber(payload: number): void {
|
|
591
|
-
this.currentPageNumber = payload
|
|
592
|
-
},
|
|
593
|
-
setOrientationValue(payload: string | null): void {
|
|
594
|
-
this.orientationValue = payload
|
|
595
|
-
},
|
|
596
|
-
|
|
597
|
-
// Load Unsplash images
|
|
598
|
-
async setLoadUnsplashImages(payload: LoadUnsplashImagesPayload): Promise<void> {
|
|
599
|
-
this.setUnsplashImages({
|
|
600
|
-
fetchedMedia: null,
|
|
601
|
-
isError: null,
|
|
602
|
-
error: null,
|
|
603
|
-
errors: null,
|
|
604
|
-
isLoading: true,
|
|
605
|
-
isSuccess: null,
|
|
606
|
-
})
|
|
607
|
-
|
|
608
|
-
const orientationType = payload.orientation ? `&orientation=${payload.orientation}` : ''
|
|
609
|
-
|
|
610
|
-
const unsplashKey = import.meta.env.VITE_UNSPLASH_KEY as string
|
|
611
|
-
|
|
612
|
-
try {
|
|
613
|
-
await handleGetImages(
|
|
614
|
-
`https://api.unsplash.com/search/photos?page=${payload.currentPage}&per_page=24&query=${payload.searchTerm || 'a'}${orientationType}`,
|
|
615
|
-
{
|
|
616
|
-
headers: {
|
|
617
|
-
'Accept-Version': 'v1',
|
|
618
|
-
Authorization: unsplashKey,
|
|
619
|
-
},
|
|
620
|
-
},
|
|
621
|
-
{ additionalCallTime: 500 },
|
|
622
|
-
)
|
|
623
|
-
} catch (err) {
|
|
624
|
-
console.log(`Error: ${err}`)
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
// Update state directly instead of committing mutations
|
|
628
|
-
this.setUnsplashImages({
|
|
629
|
-
fetchedMedia: fetchedMedia.value,
|
|
630
|
-
isError: isErrorImages.value,
|
|
631
|
-
error: errorImages.value,
|
|
632
|
-
errors: errorsImages.value,
|
|
633
|
-
isLoading: isLoadingImages.value,
|
|
634
|
-
isSuccess: isSuccessImages.value,
|
|
635
|
-
})
|
|
636
|
-
},
|
|
637
454
|
},
|
|
638
455
|
})
|
package/src/types/index.ts
CHANGED
|
@@ -27,8 +27,6 @@ export interface PageBuilderStateStore {
|
|
|
27
27
|
getFontDesktop: string | null
|
|
28
28
|
getFontTablet: string | null
|
|
29
29
|
getFontMobile: string | null
|
|
30
|
-
getUpdateOrCreate: string
|
|
31
|
-
getCurrentResourceData: { title: string; id: number } | null
|
|
32
30
|
setElement: (element: HTMLElement | null) => void
|
|
33
31
|
setMenuRight: (value: boolean) => void
|
|
34
32
|
setComponent: (component: ComponentObject | null) => void
|
|
@@ -57,7 +55,6 @@ export interface PageBuilderStateStore {
|
|
|
57
55
|
setPushComponents: (payload: SetPushComponentsPayload) => void
|
|
58
56
|
setLocalStorageItemName: (name: string | null) => void
|
|
59
57
|
setUpdateOrCreate: (mode: string) => void
|
|
60
|
-
setCurrentResourceData: (data: { title: string; id: number } | null) => void
|
|
61
58
|
setFontWeight: (weight: string) => void
|
|
62
59
|
setFontFamily: (family: string) => void
|
|
63
60
|
setFontStyle: (style: string) => void
|
|
@@ -94,15 +91,21 @@ export interface PageBuilderUser {
|
|
|
94
91
|
name: string
|
|
95
92
|
}
|
|
96
93
|
|
|
97
|
-
//
|
|
98
|
-
export interface
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
94
|
+
// Page Builder Configuration interface
|
|
95
|
+
export interface PageBuilderConfig {
|
|
96
|
+
updateOrCreate?: 'create' | 'update'
|
|
97
|
+
pageBuilderLogo?: string
|
|
98
|
+
resourceData?: { title: string; id: number } | null
|
|
99
|
+
userForPageBuilder?: { name: string } | null
|
|
103
100
|
[key: string]: unknown
|
|
101
|
+
userSettings: {
|
|
102
|
+
theme: 'light' | 'dark' | 'auto'
|
|
103
|
+
language: string
|
|
104
|
+
notifications?: boolean
|
|
105
|
+
autoSave: boolean
|
|
106
|
+
[key: string]: unknown
|
|
107
|
+
}
|
|
104
108
|
}
|
|
105
|
-
|
|
106
109
|
// Tailwind utility interfaces
|
|
107
110
|
export interface TailwindColors {
|
|
108
111
|
backgroundColorVariables: string[]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import tailwindCSS from '
|
|
1
|
+
import tailwindCSS from '../../css/app.css?inline'
|
|
2
2
|
|
|
3
3
|
const fullHTMLContent = function (HTML: string): string {
|
|
4
4
|
return `<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>${tailwindCSS}</style></head><body>${HTML}</body></html>`
|
|
@@ -16,7 +16,7 @@ const componentHelpers: ComponentHelper[] = [
|
|
|
16
16
|
Turpis tincidunt id aliquet risus feugiat in ante. Tincidunt dui ut ornare lectus sit. Ipsum dolor sit amet consectetur. Viverra ipsum nunc aliquet bibendum enim facilisis gravida neque convallis.<br><br>Dignissim sodales ut eu sem integer vitae justo eget magna.
|
|
17
17
|
Ac turpis egestas maecenas pharetra convallis. Mauris sit amet massa vitae. Ut tellus elementum sagittis vitae et. Sed risus ultricies tristique nulla aliquet enim tortor. Nunc mattis enim ut tellus elementum sagittis vitae et leo. Quis vel eros donec ac odio tempor.
|
|
18
18
|
Faucibus scelerisque eleifend donec pretium. <br><br>Adipiscing bibendum est ultricies integer quis auctor elit. Vestibulum morbi blandit cursus risus at ultrices mi tempus imperdiet. Id porta nibh venenatis cras sed felis eget. Gravida dictum fusce ut placerat orci nulla.
|
|
19
|
-
|
|
19
|
+
Sunt in culpa qui officia deserunt nisi vitae suscipit tellus mauris. <br><br></p><p><strong>List</strong></p><ul><li><p>Integer enim neque volutpat ac tincidunt vitae semper quis. Sit amet consectetur adipiscing elit pellentesque.</p></li><li><p>Urna cursus eget nunc scelerisque viverra.
|
|
20
20
|
Cursus metus aliquam eleifend mi in nulla posuere. Lobortis elementum nibh tellus molestie nunc non blandit massa.</p></li><li><p>Sodales ut eu sem integer vitae justo eget magna. Scelerisque felis imperdiet proin fermentum leo vel orci. Nunc id cursus metus aliquam eleifend.</p></li></ul>
|
|
21
21
|
</div>
|
|
22
22
|
</div>
|
|
@@ -31,7 +31,7 @@ const componentHelpers: ComponentHelper[] = [
|
|
|
31
31
|
`,
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
|
-
html_code: `<section><div class="relative py-4"><div class="mx-auto max-w-7xl lg:px-4 px-2"><div class="break-words"><h2>
|
|
34
|
+
html_code: `<section><div class="relative py-4"><div class="mx-auto max-w-7xl lg:px-4 px-2"><div class="break-words"><h2>Sunt in culpa qui officia deserunt</h2></div></div></div></section>`,
|
|
35
35
|
id: null,
|
|
36
36
|
title: 'Header H2',
|
|
37
37
|
icon: `
|
|
@@ -41,7 +41,7 @@ const componentHelpers: ComponentHelper[] = [
|
|
|
41
41
|
`,
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
|
-
html_code: `<section><div class="relative py-4"><div class="mx-auto max-w-7xl lg:px-4 px-2"><div class="break-words"><h3>
|
|
44
|
+
html_code: `<section><div class="relative py-4"><div class="mx-auto max-w-7xl lg:px-4 px-2"><div class="break-words"><h3>Sunt in culpa qui officia deserunt</h3></div></div></div></section>`,
|
|
45
45
|
id: null,
|
|
46
46
|
title: 'Header H3',
|
|
47
47
|
icon: `
|
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import { ref } from 'vue'
|
|
2
|
-
import type { Ref } from 'vue'
|
|
3
|
-
import { usePromise } from '@/composables/usePromise'
|
|
4
|
-
import { isObject } from '@/composables/isObject'
|
|
5
|
-
|
|
6
|
-
// Type definitions
|
|
7
|
-
interface CustomFetchOptions {
|
|
8
|
-
abortTimeoutTime?: number
|
|
9
|
-
additionalCallTime?: number
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface VueFetchReturn {
|
|
13
|
-
isSuccess: Ref<boolean>
|
|
14
|
-
isLoading: Ref<boolean>
|
|
15
|
-
isError: Ref<boolean>
|
|
16
|
-
error: Ref<string | null>
|
|
17
|
-
errors: Ref<unknown>
|
|
18
|
-
handleData: (
|
|
19
|
-
url: string,
|
|
20
|
-
fetchOptions?: RequestInit,
|
|
21
|
-
customFetchOptions?: CustomFetchOptions,
|
|
22
|
-
) => Promise<unknown>
|
|
23
|
-
fetchedData: Ref<unknown>
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export const vueFetch = function vueFetch(): VueFetchReturn {
|
|
27
|
-
// Initializing state management references
|
|
28
|
-
const isSuccess: Ref<boolean> = ref(false)
|
|
29
|
-
const isLoading: Ref<boolean> = ref(false)
|
|
30
|
-
const isError: Ref<boolean> = ref(false)
|
|
31
|
-
const error: Ref<string | null> = ref(null)
|
|
32
|
-
const errors: Ref<unknown> = ref(null)
|
|
33
|
-
const goDirectToError: Ref<boolean> = ref(false)
|
|
34
|
-
const fetchedData: Ref<unknown> = ref(null)
|
|
35
|
-
const streamAlreadyRead: Ref<boolean | null> = ref(null)
|
|
36
|
-
const response: Ref<Response | null> = ref(null)
|
|
37
|
-
|
|
38
|
-
const additionalTime: Ref<number | null> = ref(null)
|
|
39
|
-
const abortTimeout: Ref<number | null> = ref(null)
|
|
40
|
-
|
|
41
|
-
// Function to handle data fetching and state updates
|
|
42
|
-
const handleData = async function (
|
|
43
|
-
url: string,
|
|
44
|
-
fetchOptions: RequestInit = {},
|
|
45
|
-
customFetchOptions: CustomFetchOptions = {},
|
|
46
|
-
): Promise<unknown> {
|
|
47
|
-
isSuccess.value = false
|
|
48
|
-
isLoading.value = false
|
|
49
|
-
isError.value = false
|
|
50
|
-
error.value = null
|
|
51
|
-
errors.value = null
|
|
52
|
-
goDirectToError.value = false
|
|
53
|
-
fetchedData.value = null
|
|
54
|
-
streamAlreadyRead.value = null
|
|
55
|
-
response.value = null
|
|
56
|
-
|
|
57
|
-
// Initialize or set timeout and additional time values
|
|
58
|
-
abortTimeout.value = customFetchOptions.abortTimeoutTime ?? 4000
|
|
59
|
-
additionalTime.value = customFetchOptions.additionalCallTime ?? 0
|
|
60
|
-
|
|
61
|
-
// Initializing fetch operation control parameters
|
|
62
|
-
const controller = new AbortController()
|
|
63
|
-
|
|
64
|
-
// Abort fetch operation after the specified timeout
|
|
65
|
-
const timer = setTimeout(() => {
|
|
66
|
-
controller.abort()
|
|
67
|
-
}, abortTimeout.value)
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
// Begin fetch operation
|
|
71
|
-
isLoading.value = true
|
|
72
|
-
const promise = usePromise(additionalTime.value)
|
|
73
|
-
await promise
|
|
74
|
-
|
|
75
|
-
// Check for abort signal and handle accordingly
|
|
76
|
-
if (controller.signal.aborted) {
|
|
77
|
-
clearTimeout(timer)
|
|
78
|
-
isLoading.value = false
|
|
79
|
-
isError.value = false
|
|
80
|
-
goDirectToError.value = true
|
|
81
|
-
|
|
82
|
-
throw new Error('Error 500. Loading time exceeded.')
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Fetch and handle response
|
|
86
|
-
response.value = await fetch(url, {
|
|
87
|
-
...fetchOptions,
|
|
88
|
-
signal: controller.signal,
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
// Check if the fetch request was successful. If not, throw an error
|
|
92
|
-
if (response.value.status !== 200 && response.value.status !== 201) {
|
|
93
|
-
throw new Error(`${response.value.status}. ${response.value.statusText}`)
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Parse JSON response when content-type is 'application/json'
|
|
97
|
-
const contentType = response.value.headers.get('content-type') || ''
|
|
98
|
-
|
|
99
|
-
// Content-Type 'application/json'
|
|
100
|
-
if (contentType.includes('application/json')) {
|
|
101
|
-
streamAlreadyRead.value = true
|
|
102
|
-
clearTimeout(timer)
|
|
103
|
-
isSuccess.value = true
|
|
104
|
-
isLoading.value = false
|
|
105
|
-
isError.value = false
|
|
106
|
-
|
|
107
|
-
fetchedData.value = await response.value.json()
|
|
108
|
-
return fetchedData.value
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Content-Type 'text/plain' or 'text/html'
|
|
112
|
-
if (contentType.includes('text/plain') || contentType.includes('text/html')) {
|
|
113
|
-
streamAlreadyRead.value = true
|
|
114
|
-
clearTimeout(timer)
|
|
115
|
-
isSuccess.value = true
|
|
116
|
-
isLoading.value = false
|
|
117
|
-
isError.value = false
|
|
118
|
-
|
|
119
|
-
fetchedData.value = await response.value.text()
|
|
120
|
-
return fetchedData.value
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Handle non-GET requests without 'application/json', 'text/plain' or 'text/html'
|
|
124
|
-
if (
|
|
125
|
-
fetchOptions?.method !== 'GET' &&
|
|
126
|
-
fetchOptions?.method !== 'get' &&
|
|
127
|
-
fetchOptions?.method !== undefined
|
|
128
|
-
) {
|
|
129
|
-
clearTimeout(timer)
|
|
130
|
-
isSuccess.value = true
|
|
131
|
-
isLoading.value = false
|
|
132
|
-
isError.value = false
|
|
133
|
-
fetchedData.value = 'Your request was processed successfully.'
|
|
134
|
-
return 'Your request was processed successfully.'
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Handle GET requests without 'application/json' content-type
|
|
138
|
-
clearTimeout(timer)
|
|
139
|
-
isSuccess.value = true
|
|
140
|
-
isLoading.value = false
|
|
141
|
-
isError.value = false
|
|
142
|
-
goDirectToError.value = true
|
|
143
|
-
throw new Error(
|
|
144
|
-
"Error 500. The request header must contain 'application/json', 'text/plain' or 'text/html'",
|
|
145
|
-
)
|
|
146
|
-
} catch (err: unknown) {
|
|
147
|
-
clearTimeout(timer)
|
|
148
|
-
isSuccess.value = false
|
|
149
|
-
isLoading.value = false
|
|
150
|
-
|
|
151
|
-
// Set default error message
|
|
152
|
-
isError.value = true
|
|
153
|
-
const errorMessage = err instanceof Error ? err.message : String(err)
|
|
154
|
-
error.value = `Not able to fetch data. Error status: ${errorMessage}.`
|
|
155
|
-
|
|
156
|
-
if (response.value) {
|
|
157
|
-
// Get content type of the response
|
|
158
|
-
const contentType = response.value.headers.get('content-type') || ''
|
|
159
|
-
|
|
160
|
-
if (contentType.includes('application/json') && !streamAlreadyRead.value) {
|
|
161
|
-
// Handle errors when content type is 'application/json'
|
|
162
|
-
if (goDirectToError.value !== true) {
|
|
163
|
-
try {
|
|
164
|
-
// Parse the response body as JSON
|
|
165
|
-
const collectingErrorsJson = await response.value.json()
|
|
166
|
-
|
|
167
|
-
// Collect backend form validation errors
|
|
168
|
-
errors.value = collectingErrorsJson
|
|
169
|
-
|
|
170
|
-
// Handle different types of error messages
|
|
171
|
-
|
|
172
|
-
// If the error message is a string, handle it accordingly
|
|
173
|
-
if (typeof collectingErrorsJson === 'string') {
|
|
174
|
-
// Set error message when error body is a string
|
|
175
|
-
isError.value = true
|
|
176
|
-
error.value = `Not able to fetch data. Error status: ${errorMessage}. ${collectingErrorsJson}`
|
|
177
|
-
}
|
|
178
|
-
// If the error message is an array, handle it accordingly
|
|
179
|
-
else if (Array.isArray(collectingErrorsJson)) {
|
|
180
|
-
// Set error message when error body is an array
|
|
181
|
-
isError.value = true
|
|
182
|
-
error.value = `Not able to fetch data. Error status: ${errorMessage}. ${collectingErrorsJson.join(' ')}`
|
|
183
|
-
}
|
|
184
|
-
// If the error message is an object, handle it accordingly
|
|
185
|
-
else if (isObject(collectingErrorsJson)) {
|
|
186
|
-
const errorsKeys = Object.keys(collectingErrorsJson)
|
|
187
|
-
const errorsValues = Object.values(collectingErrorsJson)
|
|
188
|
-
|
|
189
|
-
// If there are no errors, handle it accordingly
|
|
190
|
-
if (errorsKeys.length === 0) {
|
|
191
|
-
// Set error message when error body is an empty object
|
|
192
|
-
isError.value = true
|
|
193
|
-
error.value = `Not able to fetch data. Error status: ${response.value.status}.`
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// If there are errors, handle them accordingly
|
|
197
|
-
if (errorsKeys.length > 0) {
|
|
198
|
-
for (let i = 0; i < errorsKeys.length; i++) {
|
|
199
|
-
if (Array.isArray(errorsValues[i]) || isObject(errorsValues[i])) {
|
|
200
|
-
// Set error message when encountering a nested object or array
|
|
201
|
-
isError.value = true
|
|
202
|
-
error.value = `Not able to fetch data. Error status: ${errorMessage}`
|
|
203
|
-
break
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// If the error is neither an array nor an object, handle it accordingly
|
|
207
|
-
if (!Array.isArray(errorsValues[i]) && !isObject(errorsValues[i])) {
|
|
208
|
-
const errorObjToString = Object.values(collectingErrorsJson).join(' ')
|
|
209
|
-
// Set error message when error body is a flat object
|
|
210
|
-
isError.value = true
|
|
211
|
-
error.value = `Not able to fetch data. Error status: ${errorMessage}. ${errorObjToString}`
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
} catch {
|
|
217
|
-
// Handle JSON parsing error
|
|
218
|
-
error.value = `Not able to fetch data. Error status: ${errorMessage}`
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// If the response's Content-Type text/plain, handle it accordingly
|
|
224
|
-
if (contentType.includes('text/plain') && !streamAlreadyRead.value) {
|
|
225
|
-
try {
|
|
226
|
-
const plainText = await response.value.text()
|
|
227
|
-
// Remove HTML tags using a regular expression
|
|
228
|
-
const cleanedText = plainText.replace(/<\/?[^>]+(>|$)/g, '')
|
|
229
|
-
error.value = `Error: ${cleanedText}`
|
|
230
|
-
} catch {
|
|
231
|
-
// Handle text parsing error
|
|
232
|
-
error.value = `Not able to fetch data. Error status: ${errorMessage}`
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// If the response's Content-Type text/html, handle it accordingly
|
|
237
|
-
if (contentType.includes('text/html') && !streamAlreadyRead.value) {
|
|
238
|
-
try {
|
|
239
|
-
const htmlContent = await response.value.text()
|
|
240
|
-
// Remove HTML tags using a regular expression
|
|
241
|
-
const cleanedText = htmlContent.replace(/<\/?[^>]+(>|$)/g, '')
|
|
242
|
-
error.value = `Error: ${cleanedText}`
|
|
243
|
-
} catch {
|
|
244
|
-
// Handle HTML parsing error
|
|
245
|
-
error.value = `Not able to fetch data. Error status: ${errorMessage}`
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (
|
|
250
|
-
(!contentType.includes('application/json') &&
|
|
251
|
-
!contentType.includes('text/plain') &&
|
|
252
|
-
!contentType.includes('text/html')) ||
|
|
253
|
-
goDirectToError.value
|
|
254
|
-
) {
|
|
255
|
-
isError.value = true
|
|
256
|
-
error.value = `Not able to fetch data. Error status: ${errorMessage}`
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Rethrow the error for further handling
|
|
260
|
-
throw err
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Rethrow the error if no response
|
|
264
|
-
throw err
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// Return the state variables and the fetch function
|
|
269
|
-
return {
|
|
270
|
-
isSuccess,
|
|
271
|
-
isLoading,
|
|
272
|
-
isError,
|
|
273
|
-
error,
|
|
274
|
-
errors,
|
|
275
|
-
handleData,
|
|
276
|
-
fetchedData,
|
|
277
|
-
}
|
|
278
|
-
}
|