Welcome to mirror list, hosted at ThFree Co, Russian Federation.

scope.js « src « alpinejs « packages « alpinejs - github.com/gohugoio/hugo-mod-jslibs-dist.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: abceae667c5a97995e07cb8eff93a00ebda73b63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

export function scope(node) {
    return mergeProxies(closestDataStack(node))
}

export function addScopeToNode(node, data, referenceNode) {
    node._x_dataStack = [data, ...closestDataStack(referenceNode || node)]

    return () => {
        node._x_dataStack = node._x_dataStack.filter(i => i !== data)
    }
}

export function hasScope(node) {
    return !! node._x_dataStack
}

export function refreshScope(element, scope) {
    let existingScope = element._x_dataStack[0]

    Object.entries(scope).forEach(([key, value]) => {
        existingScope[key] = value
    })
}

export function closestDataStack(node) {
    if (node._x_dataStack) return node._x_dataStack

    if (typeof ShadowRoot === 'function' && node instanceof ShadowRoot) {
        return closestDataStack(node.host)
    }

    if (! node.parentNode) {
        return []
    }

    return closestDataStack(node.parentNode)
}

export function closestDataProxy(el) {
    return mergeProxies(closestDataStack(el))
}

export function mergeProxies(objects) {
    let thisProxy = new Proxy({}, {
        ownKeys: () => {
            return Array.from(new Set(objects.flatMap(i => Object.keys(i))))
        },

        has: (target, name) => {
            return objects.some(obj => obj.hasOwnProperty(name))
        },

        get: (target, name) => {
            return (objects.find(obj => {
                if (obj.hasOwnProperty(name)) {
                    let descriptor = Object.getOwnPropertyDescriptor(obj, name)

                    // If we already bound this getter, don't rebind.
                    if ((descriptor.get && descriptor.get._x_alreadyBound) || (descriptor.set && descriptor.set._x_alreadyBound)) {
                        return true
                    }
                    
                    // Properly bind getters and setters to this wrapper Proxy.
                    if ((descriptor.get || descriptor.set) && descriptor.enumerable) {
                        // Only bind user-defined getters, not our magic properties.
                        let getter = descriptor.get
                        let setter = descriptor.set
                        let property = descriptor

                        getter = getter && getter.bind(thisProxy)
                        setter = setter && setter.bind(thisProxy)

                        if (getter) getter._x_alreadyBound = true
                        if (setter) setter._x_alreadyBound = true

                        Object.defineProperty(obj, name, {
                            ...property,
                            get: getter,
                            set: setter,
                        })
                    }

                    return true 
                }

                return false
            }) || {})[name]
        },

        set: (target, name, value) => {
            let closestObjectWithKey = objects.find(obj => obj.hasOwnProperty(name))

            if (closestObjectWithKey) {
                closestObjectWithKey[name] = value
            } else {
                objects[objects.length - 1][name] = value
            }

            return true
        },
    })

    return thisProxy
}