@myissue/vue-website-page-builder 3.3.96 → 3.3.98
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 +1 -1
- package/dist/style.css +1 -1
- package/dist/vue-website-page-builder.js +3681 -3572
- package/dist/vue-website-page-builder.umd.cjs +55 -55
- package/package.json +4 -4
- package/src/Components/Homepage/Footer.vue +1 -1
- package/src/Components/PageBuilder/EditorMenu/Editables/ComponentTopMenu.vue +18 -3
- package/src/Components/PageBuilder/UndoRedo/UndoRedo.vue +50 -9
- package/src/PageBuilder/PageBuilder.vue +15 -15
- package/src/css/style.css +24 -0
- package/src/services/PageBuilderService.ts +241 -70
- package/src/stores/page-builder-state.ts +12 -0
- package/src/tests/DefaultComponents/DefaultBuilderComponents.vue +1 -1
- package/src/tests/PageBuilderTest.vue +1 -1
- package/src/tests/componentsArray.test.json +12 -12
- package/src/tests/pageBuilderService.test.ts +110 -11
|
@@ -984,7 +984,6 @@ export class PageBuilderService {
|
|
|
984
984
|
await this.handleAutoSave()
|
|
985
985
|
}
|
|
986
986
|
|
|
987
|
-
private historyIndex: number = -1
|
|
988
987
|
private getHistoryBaseKey(): string | null {
|
|
989
988
|
return this.getLocalStorageItemName.value
|
|
990
989
|
}
|
|
@@ -993,7 +992,8 @@ export class PageBuilderService {
|
|
|
993
992
|
const baseKey = this.getHistoryBaseKey()
|
|
994
993
|
if (baseKey) {
|
|
995
994
|
const history = LocalStorageManager.getHistory(baseKey)
|
|
996
|
-
this.
|
|
995
|
+
this.pageBuilderStateStore.setHistoryIndex(history.length - 1)
|
|
996
|
+
this.pageBuilderStateStore.setHistoryLength(history.length)
|
|
997
997
|
}
|
|
998
998
|
}
|
|
999
999
|
|
|
@@ -1043,9 +1043,11 @@ export class PageBuilderService {
|
|
|
1043
1043
|
/**
|
|
1044
1044
|
* Manually saves the current page builder content to local storage.
|
|
1045
1045
|
*/
|
|
1046
|
-
public handleManualSave = async () => {
|
|
1046
|
+
public handleManualSave = async (doNoClearHTML?: boolean) => {
|
|
1047
1047
|
this.pageBuilderStateStore.setIsSaving(true)
|
|
1048
|
-
|
|
1048
|
+
if (!doNoClearHTML) {
|
|
1049
|
+
this.clearHtmlSelection()
|
|
1050
|
+
}
|
|
1049
1051
|
this.startEditing()
|
|
1050
1052
|
this.saveDomComponentsToLocalStorage()
|
|
1051
1053
|
await delay(300)
|
|
@@ -1458,9 +1460,9 @@ export class PageBuilderService {
|
|
|
1458
1460
|
if (!baseKey) return
|
|
1459
1461
|
|
|
1460
1462
|
const history = LocalStorageManager.getHistory(baseKey)
|
|
1461
|
-
if (history.length > 1 && this.
|
|
1462
|
-
this.
|
|
1463
|
-
const data = history[this.
|
|
1463
|
+
if (history.length > 1 && this.pageBuilderStateStore.getHistoryIndex > 0) {
|
|
1464
|
+
this.pageBuilderStateStore.setHistoryIndex(this.pageBuilderStateStore.getHistoryIndex - 1)
|
|
1465
|
+
const data = history[this.pageBuilderStateStore.getHistoryIndex]
|
|
1464
1466
|
const htmlString = this.renderComponentsToHtml(data.components)
|
|
1465
1467
|
await this.mountComponentsToDOM(htmlString)
|
|
1466
1468
|
}
|
|
@@ -1474,9 +1476,9 @@ export class PageBuilderService {
|
|
|
1474
1476
|
if (!baseKey) return
|
|
1475
1477
|
|
|
1476
1478
|
const history = LocalStorageManager.getHistory(baseKey)
|
|
1477
|
-
if (history.length > 0 && this.
|
|
1478
|
-
this.
|
|
1479
|
-
const data = history[this.
|
|
1479
|
+
if (history.length > 0 && this.pageBuilderStateStore.getHistoryIndex < history.length - 1) {
|
|
1480
|
+
this.pageBuilderStateStore.setHistoryIndex(this.pageBuilderStateStore.getHistoryIndex + 1)
|
|
1481
|
+
const data = history[this.pageBuilderStateStore.getHistoryIndex]
|
|
1480
1482
|
const htmlString = this.renderComponentsToHtml(data.components)
|
|
1481
1483
|
await this.mountComponentsToDOM(htmlString)
|
|
1482
1484
|
}
|
|
@@ -1632,7 +1634,7 @@ export class PageBuilderService {
|
|
|
1632
1634
|
* Reorders the currently selected component up or down in the component list.
|
|
1633
1635
|
* @param {number} direction - The direction to move the component (-1 for up, 1 for down).
|
|
1634
1636
|
*/
|
|
1635
|
-
public reorderComponent(direction: number): void {
|
|
1637
|
+
public async reorderComponent(direction: number): Promise<void> {
|
|
1636
1638
|
if (!this.getComponents.value || !this.getComponent.value) return
|
|
1637
1639
|
|
|
1638
1640
|
if (this.getComponents.value.length <= 1) return
|
|
@@ -1660,6 +1662,74 @@ export class PageBuilderService {
|
|
|
1660
1662
|
// Move the component to the new position in the array.
|
|
1661
1663
|
this.getComponents.value.splice(currentIndex, 1)
|
|
1662
1664
|
this.getComponents.value.splice(newIndex, 0, componentToMove)
|
|
1665
|
+
|
|
1666
|
+
// Wait for the DOM to update after reordering
|
|
1667
|
+
await nextTick()
|
|
1668
|
+
|
|
1669
|
+
// Scroll to the moved component
|
|
1670
|
+
const pageBuilderWrapper = document.querySelector(
|
|
1671
|
+
'#page-builder-wrapper',
|
|
1672
|
+
) as HTMLElement | null
|
|
1673
|
+
const movedComponentElement = pageBuilderWrapper?.querySelector(
|
|
1674
|
+
`section[data-componentid="${componentToMove.id}"]`,
|
|
1675
|
+
) as HTMLElement
|
|
1676
|
+
|
|
1677
|
+
if (movedComponentElement) {
|
|
1678
|
+
// Apply highlight to the moved element
|
|
1679
|
+
movedComponentElement.classList.add('pbx-reorder-highlight')
|
|
1680
|
+
|
|
1681
|
+
// Highlight its new neighbors (if they exist)
|
|
1682
|
+
const prevSibling = movedComponentElement.previousElementSibling as HTMLElement
|
|
1683
|
+
const nextSibling = movedComponentElement.nextElementSibling as HTMLElement
|
|
1684
|
+
|
|
1685
|
+
if (prevSibling && prevSibling.tagName === 'SECTION') {
|
|
1686
|
+
prevSibling.classList.add('pbx-sibling-highlight')
|
|
1687
|
+
}
|
|
1688
|
+
if (nextSibling && nextSibling.tagName === 'SECTION') {
|
|
1689
|
+
nextSibling.classList.add('pbx-sibling-highlight')
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
if (pageBuilderWrapper) {
|
|
1693
|
+
// Scroll to the moved component
|
|
1694
|
+
const topPos = movedComponentElement.offsetTop - pageBuilderWrapper.offsetTop
|
|
1695
|
+
pageBuilderWrapper.scrollTop = topPos - pageBuilderWrapper.clientHeight / 2
|
|
1696
|
+
|
|
1697
|
+
// Remove highlights after a delay
|
|
1698
|
+
setTimeout(() => {
|
|
1699
|
+
movedComponentElement.classList.remove('pbx-reorder-highlight')
|
|
1700
|
+
if (prevSibling && prevSibling.tagName === 'SECTION') {
|
|
1701
|
+
prevSibling.classList.remove('pbx-sibling-highlight')
|
|
1702
|
+
}
|
|
1703
|
+
if (nextSibling && nextSibling.tagName === 'SECTION') {
|
|
1704
|
+
nextSibling.classList.remove('pbx-sibling-highlight')
|
|
1705
|
+
}
|
|
1706
|
+
}, 200)
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
/**
|
|
1712
|
+
* Checks if the currently selected component can be moved up.
|
|
1713
|
+
* @returns {boolean} True if the component can be moved up, false otherwise.
|
|
1714
|
+
*/
|
|
1715
|
+
public canMoveUp(): boolean {
|
|
1716
|
+
if (!this.getComponents.value || !this.getComponent.value) return false
|
|
1717
|
+
const currentIndex = this.getComponents.value.findIndex(
|
|
1718
|
+
(component) => component.id === this.getComponent.value?.id,
|
|
1719
|
+
)
|
|
1720
|
+
return currentIndex > 0
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
/**
|
|
1724
|
+
* Checks if the currently selected component can be moved down.
|
|
1725
|
+
* @returns {boolean} True if the component can be moved down, false otherwise.
|
|
1726
|
+
*/
|
|
1727
|
+
public canMoveDown(): boolean {
|
|
1728
|
+
if (!this.getComponents.value || !this.getComponent.value) return false
|
|
1729
|
+
const currentIndex = this.getComponents.value.findIndex(
|
|
1730
|
+
(component) => component.id === this.getComponent.value?.id,
|
|
1731
|
+
)
|
|
1732
|
+
return currentIndex < this.getComponents.value.length - 1
|
|
1663
1733
|
}
|
|
1664
1734
|
|
|
1665
1735
|
/**
|
|
@@ -1857,6 +1927,9 @@ export class PageBuilderService {
|
|
|
1857
1927
|
pagebuilder.querySelectorAll('section[data-componentid]').forEach((section) => {
|
|
1858
1928
|
const sanitizedSection = this.cloneAndRemoveSelectionAttributes(section as HTMLElement)
|
|
1859
1929
|
|
|
1930
|
+
// Remove the data-componentid attribute
|
|
1931
|
+
sanitizedSection.removeAttribute('data-componentid')
|
|
1932
|
+
|
|
1860
1933
|
componentsToSave.push({
|
|
1861
1934
|
html_code: sanitizedSection.outerHTML,
|
|
1862
1935
|
title: sanitizedSection.getAttribute('data-component-title') || 'Untitled Component',
|
|
@@ -1875,7 +1948,29 @@ export class PageBuilderService {
|
|
|
1875
1948
|
}
|
|
1876
1949
|
|
|
1877
1950
|
const baseKey = this.getHistoryBaseKey()
|
|
1951
|
+
|
|
1878
1952
|
if (baseKey) {
|
|
1953
|
+
const currentDataRaw = localStorage.getItem(baseKey)
|
|
1954
|
+
if (currentDataRaw) {
|
|
1955
|
+
const currentData = JSON.parse(currentDataRaw)
|
|
1956
|
+
|
|
1957
|
+
// Compare components
|
|
1958
|
+
const currentComponents = currentData.components || []
|
|
1959
|
+
const newComponents = dataToSave.components || []
|
|
1960
|
+
|
|
1961
|
+
const hasChanges = newComponents.some((newComponent, index) => {
|
|
1962
|
+
const currentComponent = currentComponents[index]
|
|
1963
|
+
return (
|
|
1964
|
+
!currentComponent || // New component added
|
|
1965
|
+
currentComponent.html_code !== newComponent.html_code // Component HTML changed
|
|
1966
|
+
)
|
|
1967
|
+
})
|
|
1968
|
+
|
|
1969
|
+
if (!hasChanges) {
|
|
1970
|
+
return
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1879
1974
|
localStorage.setItem(baseKey, JSON.stringify(dataToSave))
|
|
1880
1975
|
let history = LocalStorageManager.getHistory(baseKey)
|
|
1881
1976
|
|
|
@@ -1890,15 +1985,16 @@ export class PageBuilderService {
|
|
|
1890
1985
|
}
|
|
1891
1986
|
}
|
|
1892
1987
|
|
|
1893
|
-
if (this.
|
|
1894
|
-
history = history.slice(0, this.
|
|
1988
|
+
if (this.pageBuilderStateStore.getHistoryIndex < history.length - 1) {
|
|
1989
|
+
history = history.slice(0, this.pageBuilderStateStore.getHistoryIndex + 1)
|
|
1895
1990
|
}
|
|
1896
1991
|
history.push(dataToSave)
|
|
1897
1992
|
if (history.length > 10) {
|
|
1898
1993
|
history = history.slice(history.length - 10)
|
|
1899
1994
|
}
|
|
1900
1995
|
localStorage.setItem(baseKey + '-history', JSON.stringify(history))
|
|
1901
|
-
this.
|
|
1996
|
+
this.pageBuilderStateStore.setHistoryIndex(history.length - 1)
|
|
1997
|
+
this.pageBuilderStateStore.setHistoryLength(history.length)
|
|
1902
1998
|
}
|
|
1903
1999
|
}
|
|
1904
2000
|
/**
|
|
@@ -2524,6 +2620,134 @@ export class PageBuilderService {
|
|
|
2524
2620
|
}
|
|
2525
2621
|
}
|
|
2526
2622
|
|
|
2623
|
+
/**
|
|
2624
|
+
* Applies modified components by mounting them to the DOM and attaching listeners.
|
|
2625
|
+
* @param htmlString - The HTML string to apply
|
|
2626
|
+
* @returns {Promise<string | null>} - Returns error message if failed, otherwise null
|
|
2627
|
+
*/
|
|
2628
|
+
public async applyModifiedHTML(htmlString: string): Promise<string | null> {
|
|
2629
|
+
if (!htmlString || (typeof htmlString === 'string' && htmlString.length === 0)) {
|
|
2630
|
+
return 'No HTML content was provided. Please ensure a valid HTML string is passed.'
|
|
2631
|
+
}
|
|
2632
|
+
|
|
2633
|
+
// Check if the htmlString contains any <section> tags
|
|
2634
|
+
if (/<section[\s>]/i.test(htmlString)) {
|
|
2635
|
+
return 'Error: The <section> tag cannot be used as it is already included inside this component.'
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2638
|
+
const tempDiv = document.createElement('div')
|
|
2639
|
+
tempDiv.innerHTML = htmlString.trim()
|
|
2640
|
+
|
|
2641
|
+
const parsedElement = tempDiv.firstElementChild as HTMLElement | null
|
|
2642
|
+
|
|
2643
|
+
if (!parsedElement) {
|
|
2644
|
+
return 'Could not parse element from HTML string.'
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
// Replace the actual DOM element
|
|
2648
|
+
const oldElement = this.pageBuilderStateStore.getElement
|
|
2649
|
+
|
|
2650
|
+
if (oldElement && oldElement.parentElement) {
|
|
2651
|
+
oldElement.replaceWith(parsedElement)
|
|
2652
|
+
|
|
2653
|
+
// Update the element in the store (now referencing the new one)
|
|
2654
|
+
this.pageBuilderStateStore.setElement(parsedElement)
|
|
2655
|
+
}
|
|
2656
|
+
|
|
2657
|
+
await this.addListenersToEditableElements()
|
|
2658
|
+
await nextTick()
|
|
2659
|
+
return null
|
|
2660
|
+
}
|
|
2661
|
+
|
|
2662
|
+
private validateMountingHTML(
|
|
2663
|
+
htmlString: string,
|
|
2664
|
+
options?: { logError?: boolean },
|
|
2665
|
+
): string | null {
|
|
2666
|
+
// Trim HTML string
|
|
2667
|
+
const trimmedData = htmlString.trim()
|
|
2668
|
+
const openingSectionMatches = htmlString.match(/<section\b[^>]*>/gi) || []
|
|
2669
|
+
const closingSectionMatches = htmlString.match(/<\/section>/gi) || []
|
|
2670
|
+
|
|
2671
|
+
if (!htmlString || htmlString.trim().length === 0) {
|
|
2672
|
+
const error = 'No HTML content was provided. Please ensure a valid HTML string is passed.'
|
|
2673
|
+
if (options && options.logError) {
|
|
2674
|
+
console.error(error)
|
|
2675
|
+
// Behavior
|
|
2676
|
+
return error
|
|
2677
|
+
}
|
|
2678
|
+
// default behavior
|
|
2679
|
+
return error
|
|
2680
|
+
}
|
|
2681
|
+
|
|
2682
|
+
if (openingSectionMatches.length !== closingSectionMatches.length) {
|
|
2683
|
+
const error =
|
|
2684
|
+
'Uneven <section> tags detected in the provided HTML. Each component must be wrapped in its own properly paired <section>...</section>. ' +
|
|
2685
|
+
'Ensure that all <section> tags have a matching closing </section> tag.'
|
|
2686
|
+
|
|
2687
|
+
if (options && options.logError) {
|
|
2688
|
+
console.error(error)
|
|
2689
|
+
return error
|
|
2690
|
+
}
|
|
2691
|
+
|
|
2692
|
+
return error
|
|
2693
|
+
}
|
|
2694
|
+
|
|
2695
|
+
const tempDiv = document.createElement('div')
|
|
2696
|
+
tempDiv.innerHTML = trimmedData
|
|
2697
|
+
const nestedSection = tempDiv.querySelector('section section')
|
|
2698
|
+
if (nestedSection) {
|
|
2699
|
+
const error =
|
|
2700
|
+
'Nested <section> tags are not allowed. Please ensure that no <section> is placed inside another <section>.'
|
|
2701
|
+
if (options && options.logError) {
|
|
2702
|
+
console.error(error)
|
|
2703
|
+
return error
|
|
2704
|
+
}
|
|
2705
|
+
return error
|
|
2706
|
+
}
|
|
2707
|
+
|
|
2708
|
+
// Return error since JSON data has been passed to mount HTML to DOM
|
|
2709
|
+
if (trimmedData.startsWith('[') || trimmedData.startsWith('{')) {
|
|
2710
|
+
const error =
|
|
2711
|
+
'Brackets [] or curly braces {} are not valid HTML. They are used for data formats like JSON.'
|
|
2712
|
+
if (options && options.logError) {
|
|
2713
|
+
console.error(error)
|
|
2714
|
+
return error
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
return error
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
return null
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
/**
|
|
2724
|
+
* Applies modified components by mounting them to the DOM and attaching listeners.
|
|
2725
|
+
* @param htmlString - The HTML string to apply
|
|
2726
|
+
* @returns {Promise<string | null>} - Returns error message if failed, otherwise null
|
|
2727
|
+
*/
|
|
2728
|
+
public async applyModifiedComponents(htmlString: string): Promise<string | null> {
|
|
2729
|
+
// Trim HTML string
|
|
2730
|
+
const trimmedData = htmlString.trim()
|
|
2731
|
+
|
|
2732
|
+
const openingSectionMatches = htmlString.match(/<section\b[^>]*>/gi) || []
|
|
2733
|
+
|
|
2734
|
+
if (openingSectionMatches.length === 0) {
|
|
2735
|
+
const error = 'No <section> tags found. Each component must be wrapped in a <section> tag.'
|
|
2736
|
+
if (error) {
|
|
2737
|
+
return error
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
|
|
2741
|
+
const validationError = this.validateMountingHTML(trimmedData)
|
|
2742
|
+
if (validationError) return validationError
|
|
2743
|
+
|
|
2744
|
+
// also fixed to use `trimmedData`
|
|
2745
|
+
await this.mountComponentsToDOM(trimmedData)
|
|
2746
|
+
await this.addListenersToEditableElements()
|
|
2747
|
+
await nextTick()
|
|
2748
|
+
return null
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2527
2751
|
/**
|
|
2528
2752
|
* Mounts builder components to the DOM from an HTML string.
|
|
2529
2753
|
*
|
|
@@ -2542,13 +2766,11 @@ export class PageBuilderService {
|
|
|
2542
2766
|
htmlString: string,
|
|
2543
2767
|
usePassedPageSettings?: boolean,
|
|
2544
2768
|
): Promise<void> {
|
|
2769
|
+
// Trim HTML string
|
|
2545
2770
|
const trimmedData = htmlString.trim()
|
|
2546
2771
|
|
|
2547
|
-
|
|
2548
|
-
if (
|
|
2549
|
-
console.error('Error: JSON data passed to mountComponentsToDOM for the Page Builder Package.')
|
|
2550
|
-
return
|
|
2551
|
-
}
|
|
2772
|
+
const validationError = this.validateMountingHTML(trimmedData, { logError: true })
|
|
2773
|
+
if (validationError) return
|
|
2552
2774
|
|
|
2553
2775
|
// HTML string
|
|
2554
2776
|
try {
|
|
@@ -2787,57 +3009,6 @@ export class PageBuilderService {
|
|
|
2787
3009
|
}
|
|
2788
3010
|
}
|
|
2789
3011
|
|
|
2790
|
-
/**
|
|
2791
|
-
* Applies modified components by mounting them to the DOM and attaching listeners.
|
|
2792
|
-
* @param htmlString - The HTML string to apply
|
|
2793
|
-
* @returns {Promise<string | null>} - Returns error message if failed, otherwise null
|
|
2794
|
-
*/
|
|
2795
|
-
public async applyModifiedHTML(htmlString: string): Promise<string | null> {
|
|
2796
|
-
if (!htmlString || (typeof htmlString === 'string' && htmlString.length === 0)) {
|
|
2797
|
-
return 'No HTML content was provided. Please ensure a valid HTML string is passed.'
|
|
2798
|
-
}
|
|
2799
|
-
|
|
2800
|
-
const tempDiv = document.createElement('div')
|
|
2801
|
-
tempDiv.innerHTML = htmlString.trim()
|
|
2802
|
-
|
|
2803
|
-
const parsedElement = tempDiv.firstElementChild as HTMLElement | null
|
|
2804
|
-
|
|
2805
|
-
if (!parsedElement) {
|
|
2806
|
-
return 'Could not parse element from HTML string.'
|
|
2807
|
-
}
|
|
2808
|
-
|
|
2809
|
-
// Replace the actual DOM element
|
|
2810
|
-
const oldElement = this.pageBuilderStateStore.getElement
|
|
2811
|
-
|
|
2812
|
-
if (oldElement && oldElement.parentElement) {
|
|
2813
|
-
oldElement.replaceWith(parsedElement)
|
|
2814
|
-
|
|
2815
|
-
// Update the element in the store (now referencing the new one)
|
|
2816
|
-
this.pageBuilderStateStore.setElement(parsedElement)
|
|
2817
|
-
}
|
|
2818
|
-
|
|
2819
|
-
await this.addListenersToEditableElements()
|
|
2820
|
-
await nextTick()
|
|
2821
|
-
return null
|
|
2822
|
-
}
|
|
2823
|
-
|
|
2824
|
-
/**
|
|
2825
|
-
* Applies modified components by mounting them to the DOM and attaching listeners.
|
|
2826
|
-
* @param htmlString - The HTML string to apply
|
|
2827
|
-
* @returns {Promise<string | null>} - Returns error message if failed, otherwise null
|
|
2828
|
-
*/
|
|
2829
|
-
public async applyModifiedComponents(htmlString: string): Promise<string | null> {
|
|
2830
|
-
if (!htmlString || (typeof htmlString === 'string' && htmlString.length === 0)) {
|
|
2831
|
-
return 'No HTML content was provided. Please ensure a valid HTML string is passed.'
|
|
2832
|
-
}
|
|
2833
|
-
|
|
2834
|
-
await this.mountComponentsToDOM(htmlString)
|
|
2835
|
-
|
|
2836
|
-
await this.addListenersToEditableElements()
|
|
2837
|
-
await nextTick()
|
|
2838
|
-
return null
|
|
2839
|
-
}
|
|
2840
|
-
|
|
2841
3012
|
/**
|
|
2842
3013
|
* Initializes the styles for the currently selected element.
|
|
2843
3014
|
*/
|
|
@@ -65,6 +65,8 @@ interface PageBuilderState {
|
|
|
65
65
|
isResumeEditing: boolean
|
|
66
66
|
isRestoring: boolean
|
|
67
67
|
currentLanguage: string | null
|
|
68
|
+
historyIndex: number
|
|
69
|
+
historyLength: number
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
@@ -125,6 +127,8 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
125
127
|
isResumeEditing: false,
|
|
126
128
|
isRestoring: false,
|
|
127
129
|
currentLanguage: null,
|
|
130
|
+
historyIndex: -1,
|
|
131
|
+
historyLength: 0,
|
|
128
132
|
}),
|
|
129
133
|
getters: {
|
|
130
134
|
// Core Page Builder Getters
|
|
@@ -273,6 +277,8 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
273
277
|
getIsLoadingResumeEditing: (state: PageBuilderState): boolean => state.isResumeEditing,
|
|
274
278
|
getIsRestoring: (state: PageBuilderState): boolean => state.isRestoring,
|
|
275
279
|
getCurrentLanguage: (state: PageBuilderState): string | null => state.currentLanguage,
|
|
280
|
+
getHistoryIndex: (state: PageBuilderState): number => state.historyIndex,
|
|
281
|
+
getHistoryLength: (state: PageBuilderState): number => state.historyLength,
|
|
276
282
|
},
|
|
277
283
|
actions: {
|
|
278
284
|
setComponentArrayAddMethod(payload: string | null): void {
|
|
@@ -473,5 +479,11 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
473
479
|
setCurrentLanguage(payload: string): void {
|
|
474
480
|
this.currentLanguage = payload
|
|
475
481
|
},
|
|
482
|
+
setHistoryIndex(payload: number): void {
|
|
483
|
+
this.historyIndex = payload
|
|
484
|
+
},
|
|
485
|
+
setHistoryLength(payload: number): void {
|
|
486
|
+
this.historyLength = payload
|
|
487
|
+
},
|
|
476
488
|
},
|
|
477
489
|
})
|
|
@@ -147,7 +147,7 @@ const getSvgPreview = (title: string) => {
|
|
|
147
147
|
v-for="category in categories"
|
|
148
148
|
:key="category"
|
|
149
149
|
@click="selectedCategory = category"
|
|
150
|
-
class="pbx-mySecondaryButton pbx-
|
|
150
|
+
class="pbx-mySecondaryButton pbx-text-xs pbx-px-4"
|
|
151
151
|
:class="{ active: selectedCategory === category }"
|
|
152
152
|
>
|
|
153
153
|
{{ translate(category) }}
|
|
@@ -3,7 +3,7 @@ import FullWidthElement from '../Components/Layouts/FullWidthElement.vue'
|
|
|
3
3
|
import PageBuilder from '../PageBuilder/PageBuilder.vue'
|
|
4
4
|
import DemoMediaLibraryComponentTest from '../tests/TestComponents/DemoMediaLibraryComponentTest.vue'
|
|
5
5
|
import DemoBuilderComponentsTest from '../tests/TestComponents/DemoBuilderComponentsTest.vue'
|
|
6
|
-
import {
|
|
6
|
+
import { computed, watch } from 'vue'
|
|
7
7
|
import componentsArray from '../tests/componentsArray.test.json'
|
|
8
8
|
import { getPageBuilder } from '../composables/builderInstance'
|
|
9
9
|
import { useTranslations } from '../composables/useTranslations'
|
|
@@ -1,61 +1,61 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
|
-
"html_code": "<section data-
|
|
3
|
+
"html_code": "<section data-component-title=\"Header H2\"><div class=\"pbx-relative pbx-py-4\"><div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\"><div class=\"pbx-break-words pbx-text-6xl lg:pbx-text-8xl pbx-font-medium\"><h2>{{ translate('Demo Content') }}</h2></div></div></div></section>",
|
|
4
4
|
"id": "ba0e9774-3779-467c-9c9f-5c95dd47fa6d",
|
|
5
5
|
"title": "Header H2"
|
|
6
6
|
},
|
|
7
7
|
{
|
|
8
|
-
"html_code": "<section data-
|
|
8
|
+
"html_code": "<section data-component-title=\"Text\">\n <div class=\"pbx-relative pbx-py-4\">\n <div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\">\n <div><p>{{ translate('Demo Description') }}</p></div>\n </div>\n </div>\n </section>",
|
|
9
9
|
"id": "d9fe6bdb-60df-45e4-bed5-1a6f8edf28e5",
|
|
10
10
|
"title": "Text"
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
|
-
"html_code": "<section data-
|
|
13
|
+
"html_code": "<section data-component-title=\"Three Vertical Images\">\n<div class=\"pbx-w-full md:pbx-pt-12 md:pbx-pb-12 pbx-pt-4 pbx-pb-4 lg:pbx-px-4 pbx-px-2 pbx-bg-black\"><div class=\"pbx-mx-auto pbx-max-w-7xl pbx-m\"><div class=\"pbx-myPrimaryGap pbx-grid pbx-grid-cols-1 sm:pbx-grid-cols-3 lg:pbx-grid-cols-3\"> <div class=\"pbx-flex-1 pbx-py-2\"> <img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-[9/16] pbx-rounded-tl-full\" src=\"https://images.unsplash.com/photo-1632765866070-3fadf25d3d5b?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxMjh8fG1vZGVsfGVufDB8fHx8MTc0OTgzMDgzMXww&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"provider\" data-image=\"b2fb2e61-c916-4195-9cd2-c1d25747b4f7\"> </div> <div class=\"pbx-flex-1 pbx-py-2\"> <img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-[9/16] pbx-rounded-full\" src=\"https://images.unsplash.com/photo-1542513217-0b0eedf7005d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxMDR8fG1vZGVsfGVufDB8fHx8MTc0OTgzMDc5MXww&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"provider\" data-image=\"fdf36a14-f7ef-4025-942f-c87b20b18005\"> </div> <div class=\"pbx-flex-1 pbx-py-2\"> <img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-[9/16] pbx-rounded-br-full\" src=\"https://images.unsplash.com/photo-1574015974293-817f0ebebb74?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwyNnx8bW9kZWx8ZW58MHx8fHwxNzQ5ODMwNzM1fDA&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"provider\" data-image=\"618a74a7-5d41-4dce-937c-130dd7490569\"></div></div> </div></div>\n</section>",
|
|
14
14
|
"id": "0bb012a0-631a-497f-9b7f-832313b64a2b",
|
|
15
15
|
"title": "Three Vertical Images"
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
|
-
"html_code": "<section data-
|
|
18
|
+
"html_code": "<section data-component-title=\"Header H3\"><div class=\"pbx-relative pbx-py-4\"><div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\"><div class=\"pbx-break-words pbx-mt-6 pbx-font-medium pbx-text-2xl lg:pbx-text-4xl\"><h3>{{ translate('Demo Title') }}</h3></div></div></div></section>",
|
|
19
19
|
"id": "cd7e27ac-b152-4714-a5f7-5ad660f183bf",
|
|
20
20
|
"title": "Header H3"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
|
-
"html_code": "<section data-
|
|
23
|
+
"html_code": "<section data-component-title=\"Text\">\n <div class=\"pbx-relative pbx-py-4\">\n <div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\">\n <div><p>{{ translate('Demo Description Two') }}</p></div>\n </div>\n </div>\n </section>",
|
|
24
24
|
"id": "b1e75d09-0e72-4c61-a207-a97277cbbfed",
|
|
25
25
|
"title": "Text"
|
|
26
26
|
},
|
|
27
27
|
{
|
|
28
|
-
"html_code": "<section data-
|
|
28
|
+
"html_code": "<section data-component-title=\"Two Vertical Images\">\n<div class=\"pbx-w-full md:pbx-pt-12 md:pbx-pb-12 pbx-pt-4 pbx-pb-4 lg:pbx-px-4 pbx-px-2\"><div class=\"pbx-mx-auto pbx-max-w-7xl\"><div class=\"pbx-myPrimaryGap pbx-grid pbx-grid-cols-2 sm:pbx-grid-cols-2 lg:pbx-grid-cols-2\"> <div class=\"pbx-flex-1 pbx-py-2\"> <img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-[9/16] \" src=\"https://images.unsplash.com/photo-1592966719124-2ca2978ba325?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwzfHxraW5mb2xrfGVufDB8fHx8MTc0OTgzMTAzM3ww&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"provider\" data-image=\"536340a5-c7e1-479d-a2ae-a85e6dacc2df\"> </div> <div class=\"pbx-flex-1 pbx-py-2\"> <img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-[9/16] \" src=\"https://images.unsplash.com/photo-1549298222-1c31e8915347?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwzfHxtYWdhemluZSUyMGZhc2hpb258ZW58MHx8fHwxNzQ5ODMxNTEwfDA&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"provider\" data-image=\"41655496-4742-4cc6-bc3c-abe7c2b241fb\"> </div> </div> </div> </div>\n</section>",
|
|
29
29
|
"id": "d3b5a3e4-29a3-4b03-88b6-1f77d319af74",
|
|
30
30
|
"title": "Two Vertical Images"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
|
-
"html_code": "<section data-
|
|
33
|
+
"html_code": "<section data-component-title=\"Header H3\"><div class=\"pbx-relative pbx-py-4\"><div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\"><div class=\"pbx-break-words pbx-mt-6 pbx-font-medium pbx-text-2xl lg:pbx-text-4xl\"><h3>{{ translate('Demo Title Two') }}</h3></div></div></div></section>",
|
|
34
34
|
"id": "f164929b-4460-4b17-9933-119b47e8bbef",
|
|
35
35
|
"title": "Header H3"
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
|
-
"html_code": "<section data-
|
|
38
|
+
"html_code": "<section data-component-title=\"Text\">\n <div class=\"pbx-relative pbx-py-4\">\n <div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\">\n <div class=\"\"><p>{{ translate('Demo Description Three') }}</p></div>\n </div>\n </div>\n </section>",
|
|
39
39
|
"id": "fa721207-2444-4892-9de3-5260d576a34b",
|
|
40
40
|
"title": "Text"
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
|
-
"html_code": "<section data-
|
|
43
|
+
"html_code": "<section data-component-title=\"YouTube Video\">\n <div class=\"pbx-py-4\">\n <div class=\"pbx-mx-auto pbx-max-w-7xl pbx-w-full pbx-pt-6 pbx-pb-6\">\n <div id=\"youtube-video\" class=\"pbx-w-full pbx-aspect-video pbx-p-4\">\n\n <iframe frameborder=\"0\" allowfullscreen=\"\" class=\"pbx-w-full pbx-aspect-video\" src=\"https://www.youtube.com/embed/pJvwV1Fm0vU\" allow=\"accelerometer; autoplay; clipboard-write;\">\n </iframe>\n </div>\n </div>\n </div>\n </section>",
|
|
44
44
|
"id": "33a26684-eb95-43c9-adb4-d7bce0ca60f7",
|
|
45
45
|
"title": "YouTube Video"
|
|
46
46
|
},
|
|
47
47
|
{
|
|
48
|
-
"html_code": "<section data-
|
|
48
|
+
"html_code": "<section data-component-title=\"Header H3\"><div class=\"pbx-relative pbx-py-4\"><div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\"><div class=\"pbx-break-words pbx-text-2xl lg:pbx-text-4xl pbx-font-medium\"><h3>{{ translate('Demo Title Three') }}</h3></div></div></div></section>",
|
|
49
49
|
"id": "de2208e1-5b65-4302-8ffb-b9beb7d192d7",
|
|
50
50
|
"title": "Header H3"
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
|
-
"html_code": "<section data-
|
|
53
|
+
"html_code": "<section data-component-title=\"Text\">\n <div class=\"pbx-relative pbx-py-4\">\n <div class=\"pbx-mx-auto pbx-max-w-7xl lg:pbx-px-4 pbx-px-2\">\n <div><p>{{ translate('Demo Description Four') }}</p><p></p></div>\n </div>\n </div>\n </section>",
|
|
54
54
|
"id": "e9a5c794-5972-473d-8181-af4345cbaabe",
|
|
55
55
|
"title": "Text"
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
|
-
"html_code": "<
|
|
58
|
+
"html_code": "<sectio data-component-title=\"Six Square Images Grid\">\n<div class=\"pbx-w-full md:pbx-pt-12 md:pbx-pb-12 pbx-pt-4 pbx-pb-4 lg:pbx-px-4 pbx-px-2 pbx-rounded-tr-full pbx-bg-yellow-100 pbx-rounded-bl-full\">\n<div class=\"pbx-mx-auto pbx-max-w-7xl\">\n<div class=\"pbx-grid pbx-grid-cols-2 md:pbx-grid-cols-3 pbx-myPrimaryGap\">\n\n<div>\n<img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-square \" src=\"https://images.unsplash.com/photo-1616837874254-8d5aaa63e273?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxOXx8amV3ZXJseXxlbnwwfHx8fDE3NTEwMjE1MDR8MA&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"image\">\n</div>\n\n<div>\n<img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-square \" src=\"https://images.unsplash.com/photo-1608042314453-ae338d80c427?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwyfHxqZXdlcmx5fGVufDB8fHx8MTc1MTAyMTUwNHww&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"image\">\n</div>\n\n<div>\n<img class=\"pbx-object-cover pbx-w-full pbx-object-top pbx-aspect-square \" src=\"https://images.unsplash.com/photo-1621939745912-aad97fd3a34d?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHw1MXx8amV3ZXJseXxlbnwwfHx8fDE3NTEwMjE1NDN8MA&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"image\">\n</div>\n\n<div>\n<img class=\"pbx-object-cover pbx-w-full pbx-aspect-square pbx-object-bottom\" src=\"https://images.unsplash.com/photo-1617038220319-276d3cfab638?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHw1fHxqZXdlcmx5fGVufDB8fHx8MTc1MTAyMTUwNHww&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"image\">\n</div>\n\n<div>\n<img class=\"pbx-object-cover pbx-w-full pbx-aspect-square pbx-object-bottom\" src=\"https://images.unsplash.com/photo-1594924571793-f6517415f594?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHw0Nnx8amV3ZXJseXxlbnwwfHx8fDE3NTEwMjE1Mjd8MA&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"image\">\n</div>\n\n<div>\n<img class=\"pbx-object-cover pbx-w-full pbx-aspect-square pbx-object-top\" src=\"https://images.unsplash.com/photo-1683099869102-bcf8791eb0e5?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3wzMTI0Mzl8MHwxfHNlYXJjaHwxMjV8fGpld2VybHl8ZW58MHx8fHwxNzUxMDIxNTc4fDA&ixlib=rb-4.1.0&q=80&w=1080\" alt=\"image\">\n</div>\n\n</div>\n</div>\n</div>\n</sectio>",
|
|
59
59
|
"id": "7bcda060-8ed5-482f-bcf4-aa6bd7fdb193",
|
|
60
60
|
"title": "Six Square Images Grid"
|
|
61
61
|
}
|