@myissue/vue-website-page-builder 3.3.95 → 3.3.97
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/style.css +1 -1
- package/dist/vue-website-page-builder.js +6633 -6483
- package/dist/vue-website-page-builder.umd.cjs +41 -41
- package/package.json +1 -1
- package/src/Components/PageBuilder/EditorMenu/Editables/ComponentTopMenu.vue +18 -3
- package/src/Components/PageBuilder/EditorMenu/Editables/EditGetElement.vue +0 -4
- package/src/Components/PageBuilder/EditorMenu/RightSidebarEditor.vue +0 -1
- package/src/Components/PageBuilder/UndoRedo/UndoRedo.vue +87 -0
- package/src/PageBuilder/PageBuilder.vue +18 -34
- package/src/css/style.css +29 -0
- package/src/services/LocalStorageManager.ts +25 -1
- package/src/services/PageBuilderService.ts +194 -58
- package/src/stores/page-builder-state.ts +14 -24
- package/src/tests/DefaultComponents/DefaultBuilderComponents.vue +1 -1
- package/src/tests/pageBuilderService.test.ts +110 -11
- package/src/Components/PageBuilder/EditorMenu/Editables/DeleteElement.vue +0 -42
- package/src/Components/PageBuilder/EditorMenu/Editables/ElementEditor.vue +0 -62
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LocalStorageManager } from './LocalStorageManager'
|
|
1
2
|
import type {
|
|
2
3
|
BuilderResourceData,
|
|
3
4
|
ComponentObject,
|
|
@@ -60,9 +61,6 @@ export class PageBuilderService {
|
|
|
60
61
|
private getComponents: ComputedRef<ComponentObject[] | null>
|
|
61
62
|
private getComponent: ComputedRef<ComponentObject | null>
|
|
62
63
|
private getElement: ComputedRef<HTMLElement | null>
|
|
63
|
-
private getNextSibling: ComputedRef<HTMLElement | null>
|
|
64
|
-
private getParentElement: ComputedRef<HTMLElement | null>
|
|
65
|
-
private getRestoredElement: ComputedRef<string | null>
|
|
66
64
|
private getComponentArrayAddMethod: ComputedRef<string | null>
|
|
67
65
|
private NoneListernesTags: string[]
|
|
68
66
|
private hasStartedEditing: boolean = false
|
|
@@ -98,9 +96,6 @@ export class PageBuilderService {
|
|
|
98
96
|
this.getComponent = computed(() => this.pageBuilderStateStore.getComponent)
|
|
99
97
|
|
|
100
98
|
this.getElement = computed(() => this.pageBuilderStateStore.getElement)
|
|
101
|
-
this.getNextSibling = computed(() => this.pageBuilderStateStore.getNextSibling)
|
|
102
|
-
this.getParentElement = computed(() => this.pageBuilderStateStore.getParentElement)
|
|
103
|
-
this.getRestoredElement = computed(() => this.pageBuilderStateStore.getRestoredElement)
|
|
104
99
|
|
|
105
100
|
this.getComponentArrayAddMethod = computed(
|
|
106
101
|
() => this.pageBuilderStateStore.getComponentArrayAddMethod,
|
|
@@ -416,6 +411,7 @@ export class PageBuilderService {
|
|
|
416
411
|
|
|
417
412
|
// Update the localStorage key name based on the config/resource
|
|
418
413
|
this.updateLocalStorageItemName()
|
|
414
|
+
this.initializeHistory()
|
|
419
415
|
|
|
420
416
|
if (passedComponentsArray) {
|
|
421
417
|
this.savedMountComponents = passedComponentsArray
|
|
@@ -988,6 +984,19 @@ export class PageBuilderService {
|
|
|
988
984
|
await this.handleAutoSave()
|
|
989
985
|
}
|
|
990
986
|
|
|
987
|
+
private getHistoryBaseKey(): string | null {
|
|
988
|
+
return this.getLocalStorageItemName.value
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
private initializeHistory() {
|
|
992
|
+
const baseKey = this.getHistoryBaseKey()
|
|
993
|
+
if (baseKey) {
|
|
994
|
+
const history = LocalStorageManager.getHistory(baseKey)
|
|
995
|
+
this.pageBuilderStateStore.setHistoryIndex(history.length - 1)
|
|
996
|
+
this.pageBuilderStateStore.setHistoryLength(history.length)
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
|
|
991
1000
|
/**
|
|
992
1001
|
* Triggers an auto-save of the current page builder content to local storage if enabled.
|
|
993
1002
|
*/
|
|
@@ -1052,12 +1061,12 @@ export class PageBuilderService {
|
|
|
1052
1061
|
// Deep clone clone component
|
|
1053
1062
|
const clonedComponent = { ...componentObject }
|
|
1054
1063
|
|
|
1055
|
-
const
|
|
1064
|
+
const pageBuilderWrapper = document.querySelector('#page-builder-wrapper')
|
|
1056
1065
|
// scoll to top or bottom
|
|
1057
|
-
if (
|
|
1066
|
+
if (pageBuilderWrapper) {
|
|
1058
1067
|
// push to top
|
|
1059
1068
|
if (this.getComponentArrayAddMethod.value === 'unshift') {
|
|
1060
|
-
|
|
1069
|
+
pageBuilderWrapper.scrollTo({
|
|
1061
1070
|
top: 0,
|
|
1062
1071
|
behavior: 'smooth',
|
|
1063
1072
|
})
|
|
@@ -1441,6 +1450,61 @@ export class PageBuilderService {
|
|
|
1441
1450
|
.forEach((section) => section.remove())
|
|
1442
1451
|
}
|
|
1443
1452
|
}
|
|
1453
|
+
//
|
|
1454
|
+
public async undo() {
|
|
1455
|
+
this.pageBuilderStateStore.setIsLoadingGlobal(true)
|
|
1456
|
+
await delay(300)
|
|
1457
|
+
const baseKey = this.getHistoryBaseKey()
|
|
1458
|
+
if (!baseKey) return
|
|
1459
|
+
|
|
1460
|
+
const history = LocalStorageManager.getHistory(baseKey)
|
|
1461
|
+
if (history.length > 1 && this.pageBuilderStateStore.getHistoryIndex > 0) {
|
|
1462
|
+
this.pageBuilderStateStore.setHistoryIndex(this.pageBuilderStateStore.getHistoryIndex - 1)
|
|
1463
|
+
const data = history[this.pageBuilderStateStore.getHistoryIndex]
|
|
1464
|
+
const htmlString = this.renderComponentsToHtml(data.components)
|
|
1465
|
+
await this.mountComponentsToDOM(htmlString)
|
|
1466
|
+
}
|
|
1467
|
+
this.pageBuilderStateStore.setIsLoadingGlobal(false)
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
public async redo() {
|
|
1471
|
+
this.pageBuilderStateStore.setIsLoadingGlobal(true)
|
|
1472
|
+
await delay(300)
|
|
1473
|
+
const baseKey = this.getHistoryBaseKey()
|
|
1474
|
+
if (!baseKey) return
|
|
1475
|
+
|
|
1476
|
+
const history = LocalStorageManager.getHistory(baseKey)
|
|
1477
|
+
if (history.length > 0 && this.pageBuilderStateStore.getHistoryIndex < history.length - 1) {
|
|
1478
|
+
this.pageBuilderStateStore.setHistoryIndex(this.pageBuilderStateStore.getHistoryIndex + 1)
|
|
1479
|
+
const data = history[this.pageBuilderStateStore.getHistoryIndex]
|
|
1480
|
+
const htmlString = this.renderComponentsToHtml(data.components)
|
|
1481
|
+
await this.mountComponentsToDOM(htmlString)
|
|
1482
|
+
}
|
|
1483
|
+
this.pageBuilderStateStore.setIsLoadingGlobal(false)
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
private hasVisibleContent(element: HTMLElement): boolean {
|
|
1487
|
+
if (!element) return false
|
|
1488
|
+
|
|
1489
|
+
// Check for meaningful elements
|
|
1490
|
+
const meaningfulContentSelector =
|
|
1491
|
+
'img, video, iframe, input, button, a, h1, h2, h3, h4, h5, h6, p, li, blockquote, pre, code, table'
|
|
1492
|
+
if (element.querySelector(meaningfulContentSelector)) return true
|
|
1493
|
+
|
|
1494
|
+
// Check for non-empty text nodes
|
|
1495
|
+
const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null)
|
|
1496
|
+
while (walker.nextNode()) {
|
|
1497
|
+
if (walker.currentNode.nodeValue && walker.currentNode.nodeValue.trim() !== '') {
|
|
1498
|
+
return true
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
return false
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
private isSectionEmpty(section: HTMLElement): boolean {
|
|
1506
|
+
return !this.hasVisibleContent(section)
|
|
1507
|
+
}
|
|
1444
1508
|
|
|
1445
1509
|
/**
|
|
1446
1510
|
* Deletes the currently selected component from the DOM and the state.
|
|
@@ -1450,13 +1514,13 @@ export class PageBuilderService {
|
|
|
1450
1514
|
this.syncDomToStoreOnly()
|
|
1451
1515
|
await nextTick()
|
|
1452
1516
|
|
|
1453
|
-
const components = this.getComponents
|
|
1517
|
+
const components = this.pageBuilderStateStore.getComponents
|
|
1454
1518
|
|
|
1455
1519
|
if (!components) return
|
|
1456
1520
|
|
|
1457
1521
|
// Find the index of the component to be deleted.
|
|
1458
1522
|
const indexToDelete = components.findIndex(
|
|
1459
|
-
(component) => component.id === this.getComponent.value?.id,
|
|
1523
|
+
(component: ComponentObject) => component.id === this.getComponent.value?.id,
|
|
1460
1524
|
)
|
|
1461
1525
|
|
|
1462
1526
|
if (indexToDelete === -1) {
|
|
@@ -1509,15 +1573,35 @@ export class PageBuilderService {
|
|
|
1509
1573
|
return
|
|
1510
1574
|
}
|
|
1511
1575
|
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
this.
|
|
1517
|
-
|
|
1576
|
+
const parentSection = element.closest('section')
|
|
1577
|
+
|
|
1578
|
+
// If the element to be deleted is the section itself
|
|
1579
|
+
if (element.tagName === 'SECTION') {
|
|
1580
|
+
this.deleteComponentFromDOM()
|
|
1581
|
+
} else {
|
|
1582
|
+
// If the element is inside a section
|
|
1518
1583
|
element.remove()
|
|
1584
|
+
if (parentSection && this.isSectionEmpty(parentSection)) {
|
|
1585
|
+
const componentId = parentSection.getAttribute('data-componentid')
|
|
1586
|
+
if (componentId) {
|
|
1587
|
+
const components = this.pageBuilderStateStore.getComponents
|
|
1588
|
+
if (components) {
|
|
1589
|
+
const indexToDelete = components.findIndex((c: ComponentObject) => c.id === componentId)
|
|
1590
|
+
if (indexToDelete !== -1) {
|
|
1591
|
+
const newComponents = [
|
|
1592
|
+
...components.slice(0, indexToDelete),
|
|
1593
|
+
...components.slice(indexToDelete + 1),
|
|
1594
|
+
]
|
|
1595
|
+
this.pageBuilderStateStore.setComponents(newComponents)
|
|
1596
|
+
parentSection.remove() // Directly remove from DOM
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1519
1601
|
}
|
|
1520
1602
|
|
|
1603
|
+
this.handleAutoSave()
|
|
1604
|
+
|
|
1521
1605
|
// Clear the selection state.
|
|
1522
1606
|
this.pageBuilderStateStore.setComponent(null)
|
|
1523
1607
|
this.pageBuilderStateStore.setElement(null)
|
|
@@ -1530,39 +1614,6 @@ export class PageBuilderService {
|
|
|
1530
1614
|
await this.addListenersToEditableElements()
|
|
1531
1615
|
}
|
|
1532
1616
|
|
|
1533
|
-
/**
|
|
1534
|
-
* Restores the last deleted element to its previous position in the DOM.
|
|
1535
|
-
* @returns {Promise<void>}
|
|
1536
|
-
*/
|
|
1537
|
-
public async restoreDeletedElementToDOM() {
|
|
1538
|
-
// Retrieve the details of the element to be restored.
|
|
1539
|
-
const restoredHTML = this.getRestoredElement.value
|
|
1540
|
-
const parent = this.getParentElement.value
|
|
1541
|
-
const nextSibling = this.getNextSibling.value
|
|
1542
|
-
|
|
1543
|
-
if (restoredHTML && parent) {
|
|
1544
|
-
// Create a temporary container to parse the stored HTML.
|
|
1545
|
-
const container = document.createElement('div')
|
|
1546
|
-
container.innerHTML = restoredHTML
|
|
1547
|
-
|
|
1548
|
-
// Insert the restored element back into its original position.
|
|
1549
|
-
if (container.firstChild) {
|
|
1550
|
-
parent.insertBefore(container.firstChild, nextSibling)
|
|
1551
|
-
}
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
|
-
// Clear the state related to the restored element.
|
|
1555
|
-
this.pageBuilderStateStore.setParentElement(null)
|
|
1556
|
-
this.pageBuilderStateStore.setRestoredElement(null)
|
|
1557
|
-
this.pageBuilderStateStore.setNextSibling(null)
|
|
1558
|
-
this.pageBuilderStateStore.setComponent(null)
|
|
1559
|
-
this.pageBuilderStateStore.setElement(null)
|
|
1560
|
-
|
|
1561
|
-
// Wait for the DOM to update before re-attaching event listeners.
|
|
1562
|
-
await nextTick()
|
|
1563
|
-
await this.addListenersToEditableElements()
|
|
1564
|
-
}
|
|
1565
|
-
|
|
1566
1617
|
/**
|
|
1567
1618
|
* Removes a CSS class from the currently selected element.
|
|
1568
1619
|
* @param {string} userSelectedClass - The class to remove.
|
|
@@ -1581,7 +1632,7 @@ export class PageBuilderService {
|
|
|
1581
1632
|
* Reorders the currently selected component up or down in the component list.
|
|
1582
1633
|
* @param {number} direction - The direction to move the component (-1 for up, 1 for down).
|
|
1583
1634
|
*/
|
|
1584
|
-
public reorderComponent(direction: number): void {
|
|
1635
|
+
public async reorderComponent(direction: number): Promise<void> {
|
|
1585
1636
|
if (!this.getComponents.value || !this.getComponent.value) return
|
|
1586
1637
|
|
|
1587
1638
|
if (this.getComponents.value.length <= 1) return
|
|
@@ -1609,6 +1660,69 @@ export class PageBuilderService {
|
|
|
1609
1660
|
// Move the component to the new position in the array.
|
|
1610
1661
|
this.getComponents.value.splice(currentIndex, 1)
|
|
1611
1662
|
this.getComponents.value.splice(newIndex, 0, componentToMove)
|
|
1663
|
+
|
|
1664
|
+
// Wait for the DOM to update after reordering
|
|
1665
|
+
await nextTick()
|
|
1666
|
+
|
|
1667
|
+
// Scroll to the moved component
|
|
1668
|
+
const pageBuilderWrapper = document.querySelector('#page-builder-wrapper')
|
|
1669
|
+
const movedComponentElement = pageBuilderWrapper?.querySelector(
|
|
1670
|
+
`section[data-componentid="${componentToMove.id}"]`,
|
|
1671
|
+
)
|
|
1672
|
+
|
|
1673
|
+
if (movedComponentElement) {
|
|
1674
|
+
// Apply highlight to the moved element
|
|
1675
|
+
movedComponentElement.classList.add('pbx-reorder-highlight')
|
|
1676
|
+
|
|
1677
|
+
// Highlight its new neighbors (if they exist)
|
|
1678
|
+
const prevSibling = movedComponentElement.previousElementSibling as HTMLElement
|
|
1679
|
+
const nextSibling = movedComponentElement.nextElementSibling as HTMLElement
|
|
1680
|
+
|
|
1681
|
+
if (prevSibling && prevSibling.tagName === 'SECTION') {
|
|
1682
|
+
prevSibling.classList.add('pbx-sibling-highlight')
|
|
1683
|
+
}
|
|
1684
|
+
if (nextSibling && nextSibling.tagName === 'SECTION') {
|
|
1685
|
+
nextSibling.classList.add('pbx-sibling-highlight')
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
// Scroll to the moved component
|
|
1689
|
+
movedComponentElement.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
|
1690
|
+
|
|
1691
|
+
// Remove highlights after a delay
|
|
1692
|
+
setTimeout(() => {
|
|
1693
|
+
movedComponentElement.classList.remove('pbx-reorder-highlight')
|
|
1694
|
+
if (prevSibling && prevSibling.tagName === 'SECTION') {
|
|
1695
|
+
prevSibling.classList.remove('pbx-sibling-highlight')
|
|
1696
|
+
}
|
|
1697
|
+
if (nextSibling && nextSibling.tagName === 'SECTION') {
|
|
1698
|
+
nextSibling.classList.remove('pbx-sibling-highlight')
|
|
1699
|
+
}
|
|
1700
|
+
}, 1000) // Adjust delay as needed
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
/**
|
|
1705
|
+
* Checks if the currently selected component can be moved up.
|
|
1706
|
+
* @returns {boolean} True if the component can be moved up, false otherwise.
|
|
1707
|
+
*/
|
|
1708
|
+
public canMoveUp(): boolean {
|
|
1709
|
+
if (!this.getComponents.value || !this.getComponent.value) return false
|
|
1710
|
+
const currentIndex = this.getComponents.value.findIndex(
|
|
1711
|
+
(component) => component.id === this.getComponent.value?.id,
|
|
1712
|
+
)
|
|
1713
|
+
return currentIndex > 0
|
|
1714
|
+
}
|
|
1715
|
+
|
|
1716
|
+
/**
|
|
1717
|
+
* Checks if the currently selected component can be moved down.
|
|
1718
|
+
* @returns {boolean} True if the component can be moved down, false otherwise.
|
|
1719
|
+
*/
|
|
1720
|
+
public canMoveDown(): boolean {
|
|
1721
|
+
if (!this.getComponents.value || !this.getComponent.value) return false
|
|
1722
|
+
const currentIndex = this.getComponents.value.findIndex(
|
|
1723
|
+
(component) => component.id === this.getComponent.value?.id,
|
|
1724
|
+
)
|
|
1725
|
+
return currentIndex < this.getComponents.value.length - 1
|
|
1612
1726
|
}
|
|
1613
1727
|
|
|
1614
1728
|
/**
|
|
@@ -1823,10 +1937,32 @@ export class PageBuilderService {
|
|
|
1823
1937
|
pageSettings,
|
|
1824
1938
|
}
|
|
1825
1939
|
|
|
1826
|
-
const
|
|
1940
|
+
const baseKey = this.getHistoryBaseKey()
|
|
1941
|
+
if (baseKey) {
|
|
1942
|
+
localStorage.setItem(baseKey, JSON.stringify(dataToSave))
|
|
1943
|
+
let history = LocalStorageManager.getHistory(baseKey)
|
|
1827
1944
|
|
|
1828
|
-
|
|
1829
|
-
|
|
1945
|
+
const lastState = history[history.length - 1]
|
|
1946
|
+
if (lastState) {
|
|
1947
|
+
const lastComponents = JSON.stringify(lastState.components)
|
|
1948
|
+
const newComponents = JSON.stringify(dataToSave.components)
|
|
1949
|
+
const lastSettings = JSON.stringify(lastState.pageSettings)
|
|
1950
|
+
const newSettings = JSON.stringify(dataToSave.pageSettings)
|
|
1951
|
+
if (lastComponents === newComponents && lastSettings === newSettings) {
|
|
1952
|
+
return // Do not save duplicate state
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
if (this.pageBuilderStateStore.getHistoryIndex < history.length - 1) {
|
|
1957
|
+
history = history.slice(0, this.pageBuilderStateStore.getHistoryIndex + 1)
|
|
1958
|
+
}
|
|
1959
|
+
history.push(dataToSave)
|
|
1960
|
+
if (history.length > 10) {
|
|
1961
|
+
history = history.slice(history.length - 10)
|
|
1962
|
+
}
|
|
1963
|
+
localStorage.setItem(baseKey + '-history', JSON.stringify(history))
|
|
1964
|
+
this.pageBuilderStateStore.setHistoryIndex(history.length - 1)
|
|
1965
|
+
this.pageBuilderStateStore.setHistoryLength(history.length)
|
|
1830
1966
|
}
|
|
1831
1967
|
}
|
|
1832
1968
|
/**
|
|
@@ -2285,13 +2421,13 @@ export class PageBuilderService {
|
|
|
2285
2421
|
: 'push',
|
|
2286
2422
|
})
|
|
2287
2423
|
|
|
2288
|
-
const
|
|
2424
|
+
const pageBuilderWrapper = document.querySelector('#page-builder-wrapper')
|
|
2289
2425
|
// scoll to top or bottom
|
|
2290
|
-
if (
|
|
2426
|
+
if (pageBuilderWrapper) {
|
|
2291
2427
|
// push to bottom
|
|
2292
2428
|
if (this.getComponentArrayAddMethod.value === 'push') {
|
|
2293
|
-
|
|
2294
|
-
top:
|
|
2429
|
+
pageBuilderWrapper.scrollTo({
|
|
2430
|
+
top: pageBuilderWrapper.scrollHeight + 50,
|
|
2295
2431
|
behavior: 'smooth',
|
|
2296
2432
|
})
|
|
2297
2433
|
}
|
|
@@ -32,9 +32,6 @@ interface PageBuilderState {
|
|
|
32
32
|
opacity: string | null
|
|
33
33
|
backgroundOpacity: string | null
|
|
34
34
|
textAreaVueModel: string | null
|
|
35
|
-
nextSibling: HTMLElement | null
|
|
36
|
-
parentElement: HTMLElement | null
|
|
37
|
-
restoredElement: string | null
|
|
38
35
|
currentClasses: string[]
|
|
39
36
|
currentStyles: Record<string, string>
|
|
40
37
|
fontVerticalPadding: string | null
|
|
@@ -68,6 +65,8 @@ interface PageBuilderState {
|
|
|
68
65
|
isResumeEditing: boolean
|
|
69
66
|
isRestoring: boolean
|
|
70
67
|
currentLanguage: string | null
|
|
68
|
+
historyIndex: number
|
|
69
|
+
historyLength: number
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
@@ -95,9 +94,6 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
95
94
|
opacity: null,
|
|
96
95
|
backgroundOpacity: null,
|
|
97
96
|
textAreaVueModel: null,
|
|
98
|
-
nextSibling: null,
|
|
99
|
-
parentElement: null,
|
|
100
|
-
restoredElement: null,
|
|
101
97
|
currentClasses: [],
|
|
102
98
|
currentStyles: {},
|
|
103
99
|
fontVerticalPadding: null,
|
|
@@ -131,6 +127,8 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
131
127
|
isResumeEditing: false,
|
|
132
128
|
isRestoring: false,
|
|
133
129
|
currentLanguage: null,
|
|
130
|
+
historyIndex: -1,
|
|
131
|
+
historyLength: 0,
|
|
134
132
|
}),
|
|
135
133
|
getters: {
|
|
136
134
|
// Core Page Builder Getters
|
|
@@ -200,15 +198,7 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
200
198
|
getTextAreaVueModel(state: PageBuilderState): string | null {
|
|
201
199
|
return state.textAreaVueModel
|
|
202
200
|
},
|
|
203
|
-
|
|
204
|
-
return state.nextSibling
|
|
205
|
-
},
|
|
206
|
-
getParentElement(state: PageBuilderState): HTMLElement | null {
|
|
207
|
-
return state.parentElement
|
|
208
|
-
},
|
|
209
|
-
getRestoredElement(state: PageBuilderState): string | null {
|
|
210
|
-
return state.restoredElement
|
|
211
|
-
},
|
|
201
|
+
|
|
212
202
|
getCurrentClasses(state: PageBuilderState): string[] {
|
|
213
203
|
return state.currentClasses
|
|
214
204
|
},
|
|
@@ -287,6 +277,8 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
287
277
|
getIsLoadingResumeEditing: (state: PageBuilderState): boolean => state.isResumeEditing,
|
|
288
278
|
getIsRestoring: (state: PageBuilderState): boolean => state.isRestoring,
|
|
289
279
|
getCurrentLanguage: (state: PageBuilderState): string | null => state.currentLanguage,
|
|
280
|
+
getHistoryIndex: (state: PageBuilderState): number => state.historyIndex,
|
|
281
|
+
getHistoryLength: (state: PageBuilderState): number => state.historyLength,
|
|
290
282
|
},
|
|
291
283
|
actions: {
|
|
292
284
|
setComponentArrayAddMethod(payload: string | null): void {
|
|
@@ -355,15 +347,7 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
355
347
|
setTextAreaVueModel(payload: string | null): void {
|
|
356
348
|
this.textAreaVueModel = payload
|
|
357
349
|
},
|
|
358
|
-
|
|
359
|
-
this.nextSibling = payload
|
|
360
|
-
},
|
|
361
|
-
setParentElement(payload: HTMLElement | null): void {
|
|
362
|
-
this.parentElement = payload
|
|
363
|
-
},
|
|
364
|
-
setRestoredElement(payload: string | null): void {
|
|
365
|
-
this.restoredElement = payload
|
|
366
|
-
},
|
|
350
|
+
|
|
367
351
|
setClass(payload: string): void {
|
|
368
352
|
this.currentClasses = [...this.currentClasses, payload]
|
|
369
353
|
},
|
|
@@ -495,5 +479,11 @@ export const usePageBuilderStateStore = defineStore('pageBuilderState', {
|
|
|
495
479
|
setCurrentLanguage(payload: string): void {
|
|
496
480
|
this.currentLanguage = payload
|
|
497
481
|
},
|
|
482
|
+
setHistoryIndex(payload: number): void {
|
|
483
|
+
this.historyIndex = payload
|
|
484
|
+
},
|
|
485
|
+
setHistoryLength(payload: number): void {
|
|
486
|
+
this.historyLength = payload
|
|
487
|
+
},
|
|
498
488
|
},
|
|
499
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) }}
|
|
@@ -5,20 +5,119 @@ import { usePageBuilderStateStore } from '../stores/page-builder-state'
|
|
|
5
5
|
import componentsArray from './componentsArray.test.json'
|
|
6
6
|
|
|
7
7
|
// Mock store (replace with your actual store or a better mock if needed)
|
|
8
|
-
const mockStore
|
|
8
|
+
const mockStore = {
|
|
9
|
+
// Mock getters
|
|
10
|
+
getApplyImageToSelection: { src: '' },
|
|
11
|
+
getLocalStorageItemName: 'test-key',
|
|
12
|
+
getHyberlinkEnable: false,
|
|
13
|
+
getComponents: [],
|
|
14
|
+
getComponent: null,
|
|
15
|
+
getElement: null,
|
|
16
|
+
getComponentArrayAddMethod: null,
|
|
17
|
+
getShowModalTipTap: false,
|
|
18
|
+
getMenuRight: false,
|
|
19
|
+
getBorderStyle: null,
|
|
20
|
+
getBorderWidth: null,
|
|
21
|
+
getBorderColor: null,
|
|
22
|
+
getBorderRadiusGlobal: null,
|
|
23
|
+
getBorderRadiusTopLeft: null,
|
|
24
|
+
getBorderRadiusTopRight: null,
|
|
25
|
+
getBorderRadiusBottomleft: null,
|
|
26
|
+
getBorderRadiusBottomRight: null,
|
|
27
|
+
getElementContainsHyperlink: null,
|
|
28
|
+
getHyperlinkAbility: null,
|
|
29
|
+
getHyperlinkInput: null,
|
|
30
|
+
getHyperlinkMessage: null,
|
|
31
|
+
getHyperlinkError: null,
|
|
32
|
+
getOpenHyperlinkInNewTab: null,
|
|
33
|
+
getOpacity: null,
|
|
34
|
+
getBackgroundOpacity: null,
|
|
35
|
+
getTextAreaVueModel: null,
|
|
36
|
+
getCurrentClasses: [],
|
|
37
|
+
getCurrentStyles: {},
|
|
38
|
+
getFontVerticalPadding: null,
|
|
39
|
+
getFontHorizontalPadding: null,
|
|
40
|
+
getFontVerticalMargin: null,
|
|
41
|
+
getFontHorizontalMargin: null,
|
|
42
|
+
getFontStyle: null,
|
|
43
|
+
getFontFamily: null,
|
|
44
|
+
getFontWeight: null,
|
|
45
|
+
getFontBase: null,
|
|
46
|
+
getFontDesktop: null,
|
|
47
|
+
getFontTablet: null,
|
|
48
|
+
getFontMobile: null,
|
|
49
|
+
getBackgroundColor: null,
|
|
50
|
+
getTextColor: null,
|
|
51
|
+
getBasePrimaryImage: null,
|
|
52
|
+
getPageBuilderConfig: null,
|
|
53
|
+
getCurrentPreviewImage: null,
|
|
54
|
+
getBuilderStarted: false,
|
|
55
|
+
getIsLoadingGlobal: false,
|
|
56
|
+
getIsSaving: false,
|
|
57
|
+
getHasLocalDraftForUpdate: false,
|
|
58
|
+
getIsLoadingResumeEditing: false,
|
|
59
|
+
getIsRestoring: false,
|
|
60
|
+
getCurrentLanguage: null,
|
|
61
|
+
getHistoryIndex: 0,
|
|
62
|
+
getHistoryLength: 0,
|
|
63
|
+
|
|
64
|
+
// Mock actions
|
|
9
65
|
setBuilderStarted: vi.fn(),
|
|
10
66
|
setPageBuilderConfig: vi.fn(),
|
|
11
|
-
|
|
67
|
+
setHistoryIndex: vi.fn(),
|
|
68
|
+
setHistoryLength: vi.fn(),
|
|
69
|
+
setLocalStorageItemName: vi.fn(),
|
|
70
|
+
setShowModalTipTap: vi.fn(),
|
|
71
|
+
setMenuRight: vi.fn(),
|
|
72
|
+
setBorderStyle: vi.fn(),
|
|
73
|
+
setBorderWidth: vi.fn(),
|
|
74
|
+
setBorderColor: vi.fn(),
|
|
75
|
+
setBorderRadiusGlobal: vi.fn(),
|
|
76
|
+
setBorderRadiusTopLeft: vi.fn(),
|
|
77
|
+
setBorderRadiusTopRight: vi.fn(),
|
|
78
|
+
setBorderRadiusBottomleft: vi.fn(),
|
|
79
|
+
setBorderRadiusBottomRight: vi.fn(),
|
|
80
|
+
setElementContainsHyperlink: vi.fn(),
|
|
81
|
+
setHyperlinkAbility: vi.fn(),
|
|
82
|
+
setHyperlinkInput: vi.fn(),
|
|
83
|
+
setHyperlinkMessage: vi.fn(),
|
|
84
|
+
setHyperlinkError: vi.fn(),
|
|
85
|
+
setHyberlinkEnable: vi.fn(),
|
|
86
|
+
setOpenHyperlinkInNewTab: vi.fn(),
|
|
87
|
+
setOpacity: vi.fn(),
|
|
88
|
+
setBackgroundOpacity: vi.fn(),
|
|
89
|
+
setTextAreaVueModel: vi.fn(),
|
|
90
|
+
setClass: vi.fn(),
|
|
91
|
+
removeClass: vi.fn(),
|
|
92
|
+
setCurrentClasses: vi.fn(),
|
|
93
|
+
setCurrentStyles: vi.fn(),
|
|
94
|
+
setFontVerticalPadding: vi.fn(),
|
|
95
|
+
setFontHorizontalPadding: vi.fn(),
|
|
96
|
+
setFontVerticalMargin: vi.fn(),
|
|
97
|
+
setFontHorizontalMargin: vi.fn(),
|
|
98
|
+
setFontStyle: vi.fn(),
|
|
99
|
+
setFontFamily: vi.fn(),
|
|
100
|
+
setFontWeight: vi.fn(),
|
|
101
|
+
setFontBase: vi.fn(),
|
|
102
|
+
setFontDesktop: vi.fn(),
|
|
103
|
+
setFontTablet: vi.fn(),
|
|
104
|
+
setFontMobile: vi.fn(),
|
|
105
|
+
setBackgroundColor: vi.fn(),
|
|
106
|
+
setTextColor: vi.fn(),
|
|
107
|
+
setElement: vi.fn(),
|
|
108
|
+
setComponent: vi.fn(),
|
|
12
109
|
setComponents: vi.fn(),
|
|
110
|
+
setPushComponents: vi.fn(),
|
|
111
|
+
setBasePrimaryImage: vi.fn(),
|
|
112
|
+
setCurrentLayoutPreview: vi.fn(),
|
|
113
|
+
setApplyImageToSelection: vi.fn(),
|
|
114
|
+
setCurrentPreviewImage: vi.fn(),
|
|
13
115
|
setIsLoadingGlobal: vi.fn(),
|
|
14
|
-
|
|
15
|
-
setIsLoadingResumeEditing: vi.fn(),
|
|
116
|
+
setIsSaving: vi.fn(),
|
|
16
117
|
setHasLocalDraftForUpdate: vi.fn(),
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
setLocalStorageItemName: vi.fn(),
|
|
21
|
-
// ...add more as needed for your test
|
|
118
|
+
setIsLoadingResumeEditing: vi.fn(),
|
|
119
|
+
setIsRestoring: vi.fn(),
|
|
120
|
+
setCurrentLanguage: vi.fn(),
|
|
22
121
|
} as unknown as ReturnType<typeof usePageBuilderStateStore>
|
|
23
122
|
|
|
24
123
|
const configPageBuilder = {
|
|
@@ -60,7 +159,7 @@ describe('PageBuilderService', () => {
|
|
|
60
159
|
|
|
61
160
|
it('should handle missing components array gracefully', async () => {
|
|
62
161
|
const result = await service.startBuilder(configPageBuilder)
|
|
63
|
-
expect(result).toHaveProperty('
|
|
64
|
-
|
|
162
|
+
expect(result).toHaveProperty('validation.error', true)
|
|
163
|
+
expect(result).toHaveProperty('validation.reason', 'Components data must be an array.')
|
|
65
164
|
})
|
|
66
165
|
})
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import EditorAccordion from '../EditorAccordion.vue'
|
|
3
|
-
import { computed } from 'vue'
|
|
4
|
-
import { sharedPageBuilderStore } from '../../../../stores/shared-store'
|
|
5
|
-
import { getPageBuilder } from '../../../../composables/builderInstance'
|
|
6
|
-
const pageBuilderService = getPageBuilder()
|
|
7
|
-
|
|
8
|
-
// Use shared store instance
|
|
9
|
-
const pageBuilderStateStore = sharedPageBuilderStore
|
|
10
|
-
|
|
11
|
-
const getRestoredElement = computed(() => {
|
|
12
|
-
return pageBuilderStateStore.getRestoredElement
|
|
13
|
-
})
|
|
14
|
-
</script>
|
|
15
|
-
|
|
16
|
-
<template>
|
|
17
|
-
<EditorAccordion>
|
|
18
|
-
<template #title>Delete or restore</template>
|
|
19
|
-
<template #content>
|
|
20
|
-
<div class="pbx-my-2">
|
|
21
|
-
<button
|
|
22
|
-
v-if="getRestoredElement !== null"
|
|
23
|
-
@click="pageBuilderService.restoreDeletedElementToDOM"
|
|
24
|
-
type="button"
|
|
25
|
-
class="pbx-myPrimaryButton pbx-gap-2 pbx-items-center pbx-w-full"
|
|
26
|
-
>
|
|
27
|
-
<span class="material-symbols-outlined"> refresh </span>
|
|
28
|
-
Restore Element
|
|
29
|
-
</button>
|
|
30
|
-
<button
|
|
31
|
-
v-if="getRestoredElement === null"
|
|
32
|
-
@click="pageBuilderService.deleteElementFromDOM"
|
|
33
|
-
type="button"
|
|
34
|
-
class="pbx-myPrimaryDeleteButton pbx-gap-2 pbx-items-center pbx-w-full"
|
|
35
|
-
>
|
|
36
|
-
<span class="pbx-myMediumIcon material-symbols-outlined"> delete </span>
|
|
37
|
-
Delete Element
|
|
38
|
-
</button>
|
|
39
|
-
</div>
|
|
40
|
-
</template>
|
|
41
|
-
</EditorAccordion>
|
|
42
|
-
</template>
|