1
1
import { toRaw } from 'vue'
2
- import { isFunction } from '@ditojs/utils'
2
+ import { getValueAtDataPath , isFunction } from '@ditojs/utils'
3
3
import {
4
4
getItemDataPath ,
5
5
getParentItemDataPath ,
@@ -11,24 +11,37 @@ import {
11
11
12
12
const { hasOwnProperty } = Object . prototype
13
13
14
- // `DitoContext` instances are a thin wrapper around raw `context` objects,
15
- // which themselves actually inherit from the linked `component` instance, so
16
- // that they only need to provide the values that should be different than
17
- // in the underlying component. In order to not expose all fields from the
18
- // component, the wrapper is introduced:
14
+ // See also `ContextMixin`: `DitoContext` instances are a thin wrapper around
15
+ // raw `context` objects, which themselves actually inherit from the linked
16
+ // `component` instance, so that they only need to provide the values that
17
+ // should be different than in the underlying component. In order to not expose
18
+ // all fields from the component, the wrapper is introduced.
19
+
19
20
// Use WeakMap for the raw `context` objects, so we don't have to pollute the
20
21
// actual `DitoContext` instance with it.
21
22
const contexts = new WeakMap ( )
22
23
23
- function get ( context , key , defaultValue ) {
24
- let raw = toRaw ( context )
24
+ function toObject ( context ) {
25
+ const rawStart = toRaw ( context )
26
+ let raw = rawStart
25
27
let object = null
26
28
// In case `DitoContext.extend()` was used, we need to find the actual context
27
29
// object from the object's the inheritance chain:
28
- while ( raw && ! object ) {
30
+ do {
29
31
object = contexts . get ( raw )
32
+ if ( object ) break
30
33
raw = Object . getPrototypeOf ( raw )
34
+ } while ( raw )
35
+ if ( raw !== rawStart ) {
36
+ // Assign the passed context with the original object as well, so we don't
37
+ // have to search for it again:
38
+ contexts . set ( rawStart , object )
31
39
}
40
+ return object
41
+ }
42
+
43
+ function get ( context , key , defaultValue ) {
44
+ const object = toObject ( context )
32
45
const value = key in object ? object [ key ] : undefined
33
46
// If `object` explicitly sets the key to `undefined`, return it.
34
47
return value !== undefined || hasOwnProperty . call ( object , key )
@@ -39,7 +52,7 @@ function get(context, key, defaultValue) {
39
52
}
40
53
41
54
function set ( context , key , value ) {
42
- contexts . get ( toRaw ( context ) ) [ key ] = value
55
+ toObject ( context ) [ key ] = value
43
56
}
44
57
45
58
export default class DitoContext {
@@ -85,7 +98,16 @@ export default class DitoContext {
85
98
}
86
99
87
100
get value ( ) {
88
- return get ( this , 'value' , undefined )
101
+ return get (
102
+ this ,
103
+ 'value' ,
104
+ ( ) =>
105
+ // If the value is not defined on the underlying object, it's not a type
106
+ // component. If it is nested, we can still get the value from the root.
107
+ this . nested
108
+ ? getValueAtDataPath ( this . rootItem , this . dataPath )
109
+ : undefined
110
+ )
89
111
}
90
112
91
113
get dataPath ( ) {
@@ -118,10 +140,12 @@ export default class DitoContext {
118
140
119
141
// NOTE: While internally, we speak of `data`, in the API surface the
120
142
// term `item` is used for the data that relates to editing objects:
121
- // If `data` isn't provided, we can determine it from rootData & dataPath:
122
143
get item ( ) {
123
- return get ( this , 'data' , ( ) =>
124
- getItem ( this . rootItem , this . dataPath , this . nested )
144
+ return get (
145
+ this ,
146
+ 'data' ,
147
+ // If `data` isn't provided, we can determine it from rootData & dataPath:
148
+ ( ) => getItem ( this . rootItem , this . dataPath , this . nested ) || null
125
149
)
126
150
}
127
151
@@ -133,8 +157,7 @@ export default class DitoContext {
133
157
// processing with `rootData` and `dataPath`.
134
158
get parentItem ( ) {
135
159
const item = (
136
- getParentItem ( this . rootItem , this . dataPath , this . nested ) ||
137
- null
160
+ getParentItem ( this . rootItem , this . dataPath , this . nested ) || null
138
161
)
139
162
return item !== this . item ? item : null
140
163
}
0 commit comments