@getodk/xforms-engine 0.16.0 → 0.16.1
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/client/AttributeNode.d.ts +4 -3
- package/dist/index.js +272 -211
- package/dist/index.js.map +1 -1
- package/dist/instance/Attribute.d.ts +11 -23
- package/dist/instance/Group.d.ts +3 -0
- package/dist/instance/InputControl.d.ts +3 -0
- package/dist/instance/ModelValue.d.ts +4 -0
- package/dist/instance/Note.d.ts +4 -0
- package/dist/instance/PrimaryInstance.d.ts +3 -0
- package/dist/instance/RangeControl.d.ts +4 -0
- package/dist/instance/RankControl.d.ts +5 -1
- package/dist/instance/Root.d.ts +3 -0
- package/dist/instance/SelectControl.d.ts +5 -1
- package/dist/instance/TriggerControl.d.ts +4 -0
- package/dist/instance/UploadControl.d.ts +3 -0
- package/dist/instance/abstract/DescendantNode.d.ts +5 -4
- package/dist/instance/abstract/InstanceNode.d.ts +4 -3
- package/dist/instance/hierarchy.d.ts +2 -1
- package/dist/instance/repeat/RepeatInstance.d.ts +2 -0
- package/dist/integration/xpath/adapter/XFormsXPathNode.d.ts +1 -1
- package/dist/integration/xpath/adapter/kind.d.ts +5 -3
- package/dist/integration/xpath/adapter/traversal.d.ts +3 -3
- package/dist/integration/xpath/static-dom/StaticAttribute.d.ts +1 -0
- package/dist/parse/model/AttributeDefinition.d.ts +2 -0
- package/dist/solid.js +272 -211
- package/dist/solid.js.map +1 -1
- package/package.json +2 -2
- package/src/client/AttributeNode.ts +4 -3
- package/src/instance/Attribute.ts +38 -54
- package/src/instance/Group.ts +12 -4
- package/src/instance/InputControl.ts +12 -4
- package/src/instance/ModelValue.ts +13 -4
- package/src/instance/Note.ts +13 -4
- package/src/instance/PrimaryInstance.ts +12 -4
- package/src/instance/RangeControl.ts +13 -4
- package/src/instance/RankControl.ts +14 -5
- package/src/instance/Root.ts +12 -4
- package/src/instance/SelectControl.ts +14 -5
- package/src/instance/TriggerControl.ts +13 -4
- package/src/instance/UploadControl.ts +13 -3
- package/src/instance/abstract/DescendantNode.ts +4 -3
- package/src/instance/abstract/InstanceNode.ts +5 -3
- package/src/instance/attachments/buildAttributes.ts +5 -1
- package/src/instance/children/childrenInitOptions.ts +2 -1
- package/src/instance/hierarchy.ts +2 -0
- package/src/instance/repeat/RepeatInstance.ts +11 -3
- package/src/integration/xpath/adapter/XFormsXPathNode.ts +1 -0
- package/src/integration/xpath/adapter/engineDOMAdapter.ts +2 -2
- package/src/integration/xpath/adapter/kind.ts +6 -1
- package/src/integration/xpath/adapter/names.ts +1 -0
- package/src/integration/xpath/adapter/traversal.ts +5 -6
- package/src/integration/xpath/static-dom/StaticAttribute.ts +1 -0
- package/src/lib/reactivity/createInstanceValueState.ts +29 -3
- package/src/parse/model/AttributeDefinition.ts +7 -0
package/src/instance/Root.ts
CHANGED
|
@@ -12,7 +12,10 @@ import type { InstanceState } from '../client/serialization/InstanceState.ts';
|
|
|
12
12
|
import type { AncestorNodeValidationState } from '../client/validation.ts';
|
|
13
13
|
import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
|
|
14
14
|
import { createRootInstanceState } from '../lib/client-reactivity/instance-state/createRootInstanceState.ts';
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
createAttributeState,
|
|
17
|
+
type AttributeState,
|
|
18
|
+
} from '../lib/reactivity/createAttributeState.ts';
|
|
16
19
|
import type { ChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
17
20
|
import { createChildrenState } from '../lib/reactivity/createChildrenState.ts';
|
|
18
21
|
import type { MaterializedChildren } from '../lib/reactivity/materializeCurrentStateChildren.ts';
|
|
@@ -67,6 +70,7 @@ export class Root
|
|
|
67
70
|
// DescendantNode
|
|
68
71
|
protected readonly state: SharedNodeState<RootStateSpec>;
|
|
69
72
|
protected readonly engineState: EngineState<RootStateSpec>;
|
|
73
|
+
readonly attributeState: AttributeState;
|
|
70
74
|
|
|
71
75
|
override readonly hasReadonlyAncestor = () => false;
|
|
72
76
|
override readonly isSelfReadonly = () => false;
|
|
@@ -99,7 +103,7 @@ export class Root
|
|
|
99
103
|
this.classes = parent.classes;
|
|
100
104
|
|
|
101
105
|
const childrenState = createChildrenState<Root, GeneralChildNode>(this);
|
|
102
|
-
|
|
106
|
+
this.attributeState = createAttributeState(this.scope);
|
|
103
107
|
|
|
104
108
|
this.childrenState = childrenState;
|
|
105
109
|
this.languages = parent.languages;
|
|
@@ -117,7 +121,7 @@ export class Root
|
|
|
117
121
|
valueOptions: null,
|
|
118
122
|
value: null,
|
|
119
123
|
children: childrenState.childIds,
|
|
120
|
-
attributes: attributeState.getAttributes,
|
|
124
|
+
attributes: this.attributeState.getAttributes,
|
|
121
125
|
},
|
|
122
126
|
this.instanceConfig
|
|
123
127
|
);
|
|
@@ -131,7 +135,7 @@ export class Root
|
|
|
131
135
|
);
|
|
132
136
|
|
|
133
137
|
childrenState.setChildren(buildChildren(this));
|
|
134
|
-
attributeState.setAttributes(buildAttributes(this));
|
|
138
|
+
this.attributeState.setAttributes(buildAttributes(this));
|
|
135
139
|
this.validationState = createAggregatedViolations(this, this.instanceConfig);
|
|
136
140
|
this.instanceState = createRootInstanceState(this);
|
|
137
141
|
}
|
|
@@ -140,6 +144,10 @@ export class Root
|
|
|
140
144
|
return this.childrenState.getChildren();
|
|
141
145
|
}
|
|
142
146
|
|
|
147
|
+
override getAttributes(): readonly Attribute[] {
|
|
148
|
+
return this.attributeState.getAttributes();
|
|
149
|
+
}
|
|
150
|
+
|
|
143
151
|
// RootNode
|
|
144
152
|
setLanguage(language: FormLanguage): Root {
|
|
145
153
|
this.rootDocument.setLanguage(language);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type XPathChoiceNode
|
|
1
|
+
import { XPathNodeKindKey, type XPathChoiceNode } from '@getodk/xpath';
|
|
2
2
|
import type { Accessor } from 'solid-js';
|
|
3
3
|
import { createMemo } from 'solid-js';
|
|
4
4
|
import type {
|
|
@@ -14,7 +14,10 @@ import { SelectValueTypeError } from '../error/SelectValueTypeError.ts';
|
|
|
14
14
|
import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
|
|
15
15
|
import type { StaticLeafElement } from '../integration/xpath/static-dom/StaticElement.ts';
|
|
16
16
|
import { getSelectCodec } from '../lib/codecs/getSelectCodec.ts';
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
createAttributeState,
|
|
19
|
+
type AttributeState,
|
|
20
|
+
} from '../lib/reactivity/createAttributeState.ts';
|
|
18
21
|
import { createItemCollection } from '../lib/reactivity/createItemCollection.ts';
|
|
19
22
|
import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
|
|
20
23
|
import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
|
|
@@ -24,6 +27,7 @@ import { createFieldHint } from '../lib/reactivity/text/createFieldHint.ts';
|
|
|
24
27
|
import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
|
|
25
28
|
import type { SimpleAtomicState } from '../lib/reactivity/types.ts';
|
|
26
29
|
import type { SelectType } from '../parse/body/control/SelectControlDefinition.ts';
|
|
30
|
+
import type { Attribute } from './Attribute.ts';
|
|
27
31
|
import type { Root } from './Root.ts';
|
|
28
32
|
import type { ValueNodeStateSpec } from './abstract/ValueNode.ts';
|
|
29
33
|
import { ValueNode } from './abstract/ValueNode.ts';
|
|
@@ -91,6 +95,7 @@ export class SelectControl
|
|
|
91
95
|
// InstanceNode
|
|
92
96
|
protected readonly state: SharedNodeState<SelectControlStateSpec>;
|
|
93
97
|
protected readonly engineState: EngineState<SelectControlStateSpec>;
|
|
98
|
+
readonly attributeState: AttributeState;
|
|
94
99
|
|
|
95
100
|
// SelectNode
|
|
96
101
|
readonly nodeType = 'select';
|
|
@@ -110,7 +115,7 @@ export class SelectControl
|
|
|
110
115
|
|
|
111
116
|
this.appearances = definition.bodyElement.appearances;
|
|
112
117
|
this.selectType = definition.bodyElement.type;
|
|
113
|
-
|
|
118
|
+
this.attributeState = createAttributeState(this.scope);
|
|
114
119
|
|
|
115
120
|
const valueOptions = createItemCollection(this);
|
|
116
121
|
|
|
@@ -156,7 +161,7 @@ export class SelectControl
|
|
|
156
161
|
label: createNodeLabel(this, definition),
|
|
157
162
|
hint: createFieldHint(this, definition),
|
|
158
163
|
children: null,
|
|
159
|
-
attributes: attributeState.getAttributes,
|
|
164
|
+
attributes: this.attributeState.getAttributes,
|
|
160
165
|
valueOptions,
|
|
161
166
|
value: valueState,
|
|
162
167
|
instanceValue: this.getInstanceValue,
|
|
@@ -165,7 +170,7 @@ export class SelectControl
|
|
|
165
170
|
this.instanceConfig
|
|
166
171
|
);
|
|
167
172
|
|
|
168
|
-
attributeState.setAttributes(buildAttributes(this));
|
|
173
|
+
this.attributeState.setAttributes(buildAttributes(this));
|
|
169
174
|
|
|
170
175
|
this.state = state;
|
|
171
176
|
this.engineState = state.engineState;
|
|
@@ -243,4 +248,8 @@ export class SelectControl
|
|
|
243
248
|
const option = this.mapOptionsByValue().get(value);
|
|
244
249
|
return option?.label?.asString ?? null;
|
|
245
250
|
}
|
|
251
|
+
|
|
252
|
+
override getAttributes(): readonly Attribute[] {
|
|
253
|
+
return this.attributeState.getAttributes();
|
|
254
|
+
}
|
|
246
255
|
}
|
|
@@ -8,7 +8,10 @@ import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPat
|
|
|
8
8
|
import type { StaticLeafElement } from '../integration/xpath/static-dom/StaticElement.ts';
|
|
9
9
|
import type { TriggerInputValue, TriggerRuntimeValue } from '../lib/codecs/TriggerCodec.ts';
|
|
10
10
|
import { TriggerCodec } from '../lib/codecs/TriggerCodec.ts';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
createAttributeState,
|
|
13
|
+
type AttributeState,
|
|
14
|
+
} from '../lib/reactivity/createAttributeState.ts';
|
|
12
15
|
import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
|
|
13
16
|
import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
|
|
14
17
|
import type { SharedNodeState } from '../lib/reactivity/node-state/createSharedNodeState.ts';
|
|
@@ -16,6 +19,7 @@ import { createSharedNodeState } from '../lib/reactivity/node-state/createShared
|
|
|
16
19
|
import { createFieldHint } from '../lib/reactivity/text/createFieldHint.ts';
|
|
17
20
|
import { createNodeLabel } from '../lib/reactivity/text/createNodeLabel.ts';
|
|
18
21
|
import type { UnknownAppearanceDefinition } from '../parse/body/appearance/unknownAppearanceParser.ts';
|
|
22
|
+
import type { Attribute } from './Attribute.ts';
|
|
19
23
|
import type { Root } from './Root.ts';
|
|
20
24
|
import { ValueNode, type ValueNodeStateSpec } from './abstract/ValueNode.ts';
|
|
21
25
|
import { buildAttributes } from './attachments/buildAttributes.ts';
|
|
@@ -75,6 +79,7 @@ export class TriggerControl
|
|
|
75
79
|
// InstanceNode
|
|
76
80
|
protected readonly state: SharedNodeState<TriggerControlStateSpec>;
|
|
77
81
|
protected readonly engineState: EngineState<TriggerControlStateSpec>;
|
|
82
|
+
readonly attributeState: AttributeState;
|
|
78
83
|
|
|
79
84
|
// TriggerNode
|
|
80
85
|
readonly nodeType = 'trigger';
|
|
@@ -90,7 +95,7 @@ export class TriggerControl
|
|
|
90
95
|
super(parent, instanceNode, definition, codec);
|
|
91
96
|
|
|
92
97
|
this.appearances = definition.bodyElement.appearances;
|
|
93
|
-
|
|
98
|
+
this.attributeState = createAttributeState(this.scope);
|
|
94
99
|
|
|
95
100
|
const state = createSharedNodeState(
|
|
96
101
|
this.scope,
|
|
@@ -103,7 +108,7 @@ export class TriggerControl
|
|
|
103
108
|
label: createNodeLabel(this, definition),
|
|
104
109
|
hint: createFieldHint(this, definition),
|
|
105
110
|
children: null,
|
|
106
|
-
attributes: attributeState.getAttributes,
|
|
111
|
+
attributes: this.attributeState.getAttributes,
|
|
107
112
|
valueOptions: null,
|
|
108
113
|
value: this.valueState,
|
|
109
114
|
instanceValue: this.getInstanceValue,
|
|
@@ -111,13 +116,17 @@ export class TriggerControl
|
|
|
111
116
|
this.instanceConfig
|
|
112
117
|
);
|
|
113
118
|
|
|
114
|
-
attributeState.setAttributes(buildAttributes(this));
|
|
119
|
+
this.attributeState.setAttributes(buildAttributes(this));
|
|
115
120
|
|
|
116
121
|
this.state = state;
|
|
117
122
|
this.engineState = state.engineState;
|
|
118
123
|
this.currentState = state.currentState;
|
|
119
124
|
}
|
|
120
125
|
|
|
126
|
+
override getAttributes(): readonly Attribute[] {
|
|
127
|
+
return this.attributeState.getAttributes();
|
|
128
|
+
}
|
|
129
|
+
|
|
121
130
|
// TriggerNode
|
|
122
131
|
setValue(value: TriggerInputValue): Root {
|
|
123
132
|
this.setValueState(value);
|
|
@@ -9,7 +9,10 @@ import { UploadValueTypeError } from '../error/UploadValueTypeError.ts';
|
|
|
9
9
|
import type { XFormsXPathElement } from '../integration/xpath/adapter/XFormsXPathNode.ts';
|
|
10
10
|
import type { StaticLeafElement } from '../integration/xpath/static-dom/StaticElement.ts';
|
|
11
11
|
import { createValueNodeInstanceState } from '../lib/client-reactivity/instance-state/createValueNodeInstanceState.ts';
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
createAttributeState,
|
|
14
|
+
type AttributeState,
|
|
15
|
+
} from '../lib/reactivity/createAttributeState.ts';
|
|
13
16
|
import { createInstanceAttachment } from '../lib/reactivity/createInstanceAttachment.ts';
|
|
14
17
|
import type { CurrentState } from '../lib/reactivity/node-state/createCurrentState.ts';
|
|
15
18
|
import type { EngineState } from '../lib/reactivity/node-state/createEngineState.ts';
|
|
@@ -29,6 +32,7 @@ import type {
|
|
|
29
32
|
InstanceAttachment,
|
|
30
33
|
InstanceAttachmentRuntimeValue,
|
|
31
34
|
} from './attachments/InstanceAttachment.ts';
|
|
35
|
+
import { buildAttributes } from './attachments/buildAttributes.ts';
|
|
32
36
|
import type { GeneralParentNode } from './hierarchy.ts';
|
|
33
37
|
import type { EvaluationContext } from './internal-api/EvaluationContext.ts';
|
|
34
38
|
import type { InstanceAttachmentContext } from './internal-api/InstanceAttachmentContext.ts';
|
|
@@ -106,6 +110,7 @@ export class UploadControl
|
|
|
106
110
|
// InstanceNode
|
|
107
111
|
protected readonly state: SharedNodeState<UploadControlStateSpec>;
|
|
108
112
|
protected readonly engineState: EngineState<UploadControlStateSpec>;
|
|
113
|
+
readonly attributeState: AttributeState;
|
|
109
114
|
|
|
110
115
|
// InstanceValueContext
|
|
111
116
|
readonly decodeInstanceValue: DecodeInstanceValue;
|
|
@@ -136,7 +141,7 @@ export class UploadControl
|
|
|
136
141
|
const instanceAttachment = createInstanceAttachment(this);
|
|
137
142
|
|
|
138
143
|
this.instanceAttachment = instanceAttachment;
|
|
139
|
-
|
|
144
|
+
this.attributeState = createAttributeState(this.scope);
|
|
140
145
|
this.decodeInstanceValue = instanceAttachment.decodeInstanceValue;
|
|
141
146
|
this.getXPathValue = instanceAttachment.getInstanceValue;
|
|
142
147
|
|
|
@@ -153,7 +158,7 @@ export class UploadControl
|
|
|
153
158
|
children: null,
|
|
154
159
|
valueOptions: null,
|
|
155
160
|
value: instanceAttachment.valueState,
|
|
156
|
-
attributes: attributeState.getAttributes,
|
|
161
|
+
attributes: this.attributeState.getAttributes,
|
|
157
162
|
instanceValue: instanceAttachment.getInstanceValue,
|
|
158
163
|
},
|
|
159
164
|
this.instanceConfig
|
|
@@ -163,6 +168,7 @@ export class UploadControl
|
|
|
163
168
|
this.engineState = state.engineState;
|
|
164
169
|
this.currentState = state.currentState;
|
|
165
170
|
this.validation = createValidationState(this, this.instanceConfig);
|
|
171
|
+
this.attributeState.setAttributes(buildAttributes(this));
|
|
166
172
|
this.instanceState = createValueNodeInstanceState(this);
|
|
167
173
|
}
|
|
168
174
|
|
|
@@ -180,6 +186,10 @@ export class UploadControl
|
|
|
180
186
|
return [];
|
|
181
187
|
}
|
|
182
188
|
|
|
189
|
+
override getAttributes(): readonly Attribute[] {
|
|
190
|
+
return this.attributeState.getAttributes();
|
|
191
|
+
}
|
|
192
|
+
|
|
183
193
|
// UploadNode
|
|
184
194
|
setValue(value: InstanceAttachmentRuntimeValue): Root {
|
|
185
195
|
this.instanceAttachment.setValue(value);
|
|
@@ -11,12 +11,13 @@ import type {
|
|
|
11
11
|
} from '../../integration/xpath/adapter/XFormsXPathNode.ts';
|
|
12
12
|
import { XFORMS_XPATH_NODE_RANGE_KIND } from '../../integration/xpath/adapter/XFormsXPathNode.ts';
|
|
13
13
|
import type { EngineXPathEvaluator } from '../../integration/xpath/EngineXPathEvaluator.ts';
|
|
14
|
+
import type { StaticAttribute } from '../../integration/xpath/static-dom/StaticAttribute.ts';
|
|
14
15
|
import type { StaticElement } from '../../integration/xpath/static-dom/StaticElement.ts';
|
|
15
16
|
import { createComputedExpression } from '../../lib/reactivity/createComputedExpression.ts';
|
|
16
17
|
import type { ReactiveScope } from '../../lib/reactivity/scope.ts';
|
|
17
18
|
import type { AnyNodeDefinition } from '../../parse/model/NodeDefinition.ts';
|
|
18
19
|
import type { DescendantNodeInitOptions } from '../children/DescendantNodeInitOptions.ts';
|
|
19
|
-
import type { AnyChildNode,
|
|
20
|
+
import type { AnyChildNode, AnyNode, RepeatRange } from '../hierarchy.ts';
|
|
20
21
|
import type { EvaluationContext } from '../internal-api/EvaluationContext.ts';
|
|
21
22
|
import type { RepeatInstance } from '../repeat/RepeatInstance.ts';
|
|
22
23
|
import type { Root } from '../Root.ts';
|
|
@@ -63,7 +64,7 @@ export abstract class DescendantNode<
|
|
|
63
64
|
Definition extends DescendantNodeDefinition,
|
|
64
65
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
65
66
|
Spec extends DescendantNodeStateSpec<any>,
|
|
66
|
-
Parent extends
|
|
67
|
+
Parent extends AnyNode,
|
|
67
68
|
Child extends AnyChildNode | null = null,
|
|
68
69
|
>
|
|
69
70
|
extends InstanceNode<Definition, Spec, Parent, Child>
|
|
@@ -137,7 +138,7 @@ export abstract class DescendantNode<
|
|
|
137
138
|
|
|
138
139
|
constructor(
|
|
139
140
|
override readonly parent: Parent,
|
|
140
|
-
override readonly instanceNode: StaticElement | null,
|
|
141
|
+
override readonly instanceNode: StaticAttribute | StaticElement | null,
|
|
141
142
|
override readonly definition: Definition,
|
|
142
143
|
options?: DescendantNodeOptions
|
|
143
144
|
) {
|
|
@@ -28,7 +28,7 @@ import type { AnyNodeDefinition } from '../../parse/model/NodeDefinition.ts';
|
|
|
28
28
|
import type { Attribute } from '../Attribute.ts';
|
|
29
29
|
import type { PrimaryInstance } from '../PrimaryInstance.ts';
|
|
30
30
|
import type { Root } from '../Root.ts';
|
|
31
|
-
import type { AnyChildNode, AnyNode
|
|
31
|
+
import type { AnyChildNode, AnyNode } from '../hierarchy.ts';
|
|
32
32
|
import { nodeID } from '../identity.ts';
|
|
33
33
|
import type { EvaluationContext } from '../internal-api/EvaluationContext.ts';
|
|
34
34
|
import type { InstanceConfig } from '../internal-api/InstanceConfig.ts';
|
|
@@ -84,7 +84,7 @@ export type InstanceNodeCurrentState<
|
|
|
84
84
|
};
|
|
85
85
|
|
|
86
86
|
interface ComputableReferenceNode {
|
|
87
|
-
readonly parent:
|
|
87
|
+
readonly parent: AnyNode | null;
|
|
88
88
|
readonly definition: AnyNodeDefinition;
|
|
89
89
|
}
|
|
90
90
|
|
|
@@ -103,7 +103,7 @@ export abstract class InstanceNode<
|
|
|
103
103
|
Definition extends AnyNodeDefinition,
|
|
104
104
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
105
105
|
Spec extends InstanceNodeStateSpec<any>,
|
|
106
|
-
Parent extends
|
|
106
|
+
Parent extends AnyNode | null,
|
|
107
107
|
Child extends AnyChildNode | null = null,
|
|
108
108
|
>
|
|
109
109
|
implements BaseEngineNode, XFormsXPathPrimaryInstanceNode, EvaluationContext
|
|
@@ -272,4 +272,6 @@ export abstract class InstanceNode<
|
|
|
272
272
|
.map((child) => child.getXPathValue())
|
|
273
273
|
.join('');
|
|
274
274
|
}
|
|
275
|
+
|
|
276
|
+
abstract getAttributes(): readonly Attribute[];
|
|
275
277
|
}
|
|
@@ -9,7 +9,11 @@ export function buildAttributes(
|
|
|
9
9
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
10
|
owner: AnyNode | InputControl<any> | ModelValue<any> | Note<any> | RangeControl<any>
|
|
11
11
|
): Attribute[] {
|
|
12
|
-
|
|
12
|
+
const attributes = owner.definition.attributes;
|
|
13
|
+
if (!attributes) {
|
|
14
|
+
return [];
|
|
15
|
+
}
|
|
16
|
+
return Array.from(attributes.values()).map((attributeDefinition) => {
|
|
13
17
|
return new Attribute(owner, attributeDefinition, attributeDefinition.template);
|
|
14
18
|
});
|
|
15
19
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { StaticAttribute } from '../../integration/xpath/static-dom/StaticAttribute.ts';
|
|
1
2
|
import type { StaticDocument } from '../../integration/xpath/static-dom/StaticDocument.ts';
|
|
2
3
|
import type { StaticElement } from '../../integration/xpath/static-dom/StaticElement.ts';
|
|
3
4
|
import type { ModelDefinition } from '../../parse/model/ModelDefinition.ts';
|
|
@@ -37,7 +38,7 @@ const collectModelChildNodesets = (parentTemplate: StaticElement): readonly stri
|
|
|
37
38
|
type InstanceNodesByNodeset = ReadonlyMap<string, readonly [StaticElement, ...StaticElement[]]>;
|
|
38
39
|
|
|
39
40
|
const groupChildElementsByNodeset = (
|
|
40
|
-
parent: StaticDocument | StaticElement
|
|
41
|
+
parent: StaticAttribute | StaticDocument | StaticElement
|
|
41
42
|
): InstanceNodesByNodeset => {
|
|
42
43
|
const result = new Map<string, [StaticElement, ...StaticElement[]]>();
|
|
43
44
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Attribute } from './Attribute.ts';
|
|
1
2
|
import type { Group } from './Group.ts';
|
|
2
3
|
import type { AnyInputControl } from './InputControl.ts';
|
|
3
4
|
import type { AnyModelValue } from './ModelValue.ts';
|
|
@@ -23,6 +24,7 @@ export type AnyNode =
|
|
|
23
24
|
| Group
|
|
24
25
|
| RepeatRange
|
|
25
26
|
| RepeatInstance
|
|
27
|
+
| Attribute
|
|
26
28
|
| AnyNote
|
|
27
29
|
| AnyModelValue
|
|
28
30
|
| AnyInputControl
|
|
@@ -13,7 +13,10 @@ import type { AncestorNodeValidationState } from '../../client/validation.ts';
|
|
|
13
13
|
import type { XFormsXPathElement } from '../../integration/xpath/adapter/XFormsXPathNode.ts';
|
|
14
14
|
import type { StaticElement } from '../../integration/xpath/static-dom/StaticElement.ts';
|
|
15
15
|
import { createTemplatedNodeInstanceState } from '../../lib/client-reactivity/instance-state/createTemplatedNodeInstanceState.ts';
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
createAttributeState,
|
|
18
|
+
type AttributeState,
|
|
19
|
+
} from '../../lib/reactivity/createAttributeState.ts';
|
|
17
20
|
import type { ChildrenState } from '../../lib/reactivity/createChildrenState.ts';
|
|
18
21
|
import { createChildrenState } from '../../lib/reactivity/createChildrenState.ts';
|
|
19
22
|
import type { MaterializedChildren } from '../../lib/reactivity/materializeCurrentStateChildren.ts';
|
|
@@ -60,6 +63,7 @@ export class RepeatInstance
|
|
|
60
63
|
ClientReactiveSerializableTemplatedNode
|
|
61
64
|
{
|
|
62
65
|
private readonly childrenState: ChildrenState<GeneralChildNode>;
|
|
66
|
+
private readonly attributeState: AttributeState;
|
|
63
67
|
private readonly currentIndex: Accessor<number>;
|
|
64
68
|
|
|
65
69
|
override readonly [XPathNodeKindKey] = 'element';
|
|
@@ -131,7 +135,7 @@ export class RepeatInstance
|
|
|
131
135
|
this.appearances = definition.bodyElement.appearances;
|
|
132
136
|
|
|
133
137
|
const childrenState = createChildrenState<RepeatInstance, GeneralChildNode>(this);
|
|
134
|
-
|
|
138
|
+
this.attributeState = createAttributeState(this.scope);
|
|
135
139
|
|
|
136
140
|
this.childrenState = childrenState;
|
|
137
141
|
this.currentIndex = currentIndex;
|
|
@@ -147,7 +151,7 @@ export class RepeatInstance
|
|
|
147
151
|
// TODO: only-child <group><label>
|
|
148
152
|
label: createNodeLabel(this, definition),
|
|
149
153
|
hint: null,
|
|
150
|
-
attributes: attributeState.getAttributes,
|
|
154
|
+
attributes: this.attributeState.getAttributes,
|
|
151
155
|
children: childrenState.childIds,
|
|
152
156
|
valueOptions: null,
|
|
153
157
|
value: null,
|
|
@@ -192,4 +196,8 @@ export class RepeatInstance
|
|
|
192
196
|
getChildren(): readonly GeneralChildNode[] {
|
|
193
197
|
return this.childrenState.getChildren();
|
|
194
198
|
}
|
|
199
|
+
|
|
200
|
+
override getAttributes(): readonly Attribute[] {
|
|
201
|
+
return this.attributeState.getAttributes();
|
|
202
|
+
}
|
|
195
203
|
}
|
|
@@ -120,6 +120,7 @@ export interface XFormsXPathPrimaryInstanceNode extends XFormsXPathNode {
|
|
|
120
120
|
// prettier-ignore
|
|
121
121
|
export type XFormsXPathPrimaryInstanceDescendantNodeKind =
|
|
122
122
|
| XFormsXPathNodeRangeKind
|
|
123
|
+
| XPathAttributeKind
|
|
123
124
|
| XPathElementKind
|
|
124
125
|
| XPathTextKind;
|
|
125
126
|
|
|
@@ -10,10 +10,10 @@ import {
|
|
|
10
10
|
} from './names.ts';
|
|
11
11
|
import {
|
|
12
12
|
compareDocumentOrder,
|
|
13
|
+
getAttributes,
|
|
13
14
|
getChildElements,
|
|
14
15
|
getChildNodes,
|
|
15
16
|
getContainingEngineXPathDocument,
|
|
16
|
-
getEngineXPathAttributes,
|
|
17
17
|
getNamespaceDeclarations,
|
|
18
18
|
getNextSiblingElement,
|
|
19
19
|
getNextSiblingNode,
|
|
@@ -43,7 +43,7 @@ export const engineDOMAdapter: EngineDOMAdapter = {
|
|
|
43
43
|
|
|
44
44
|
// XPathTraversalAdapter
|
|
45
45
|
compareDocumentOrder,
|
|
46
|
-
getAttributes:
|
|
46
|
+
getAttributes: getAttributes,
|
|
47
47
|
getChildElements: getChildElements,
|
|
48
48
|
getChildNodes: getChildNodes,
|
|
49
49
|
getContainingDocument: getContainingEngineXPathDocument,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { XPathNodeKind } from '@getodk/xpath';
|
|
2
2
|
import { XPathNodeKindKey } from '@getodk/xpath';
|
|
3
|
+
import type { Attribute } from '../../../instance/Attribute.ts';
|
|
3
4
|
import type { AnyChildNode, AnyNode, AnyParentNode } from '../../../instance/hierarchy.ts';
|
|
4
5
|
import type { PrimaryInstance } from '../../../instance/PrimaryInstance.ts';
|
|
5
6
|
import type { StaticAttribute } from '../static-dom/StaticAttribute.ts';
|
|
@@ -7,6 +8,7 @@ import type { StaticDocument } from '../static-dom/StaticDocument.ts';
|
|
|
7
8
|
import type { StaticElement } from '../static-dom/StaticElement.ts';
|
|
8
9
|
import type { StaticText } from '../static-dom/StaticText.ts';
|
|
9
10
|
import type {
|
|
11
|
+
XFormsXPathAttribute,
|
|
10
12
|
XFormsXPathComment,
|
|
11
13
|
XFormsXPathDocument,
|
|
12
14
|
XFormsXPathElement,
|
|
@@ -17,12 +19,15 @@ export type PrimaryInstanceXPathNode = Extract<AnyNode, XFormsXPathPrimaryInstan
|
|
|
17
19
|
|
|
18
20
|
export type PrimaryInstanceXPathElement = Extract<AnyChildNode, XFormsXPathElement>;
|
|
19
21
|
|
|
22
|
+
export type PrimaryInstanceXPathAttribute = Extract<Attribute, XFormsXPathAttribute>;
|
|
23
|
+
|
|
20
24
|
export type PrimaryInstanceXPathComment = Extract<AnyChildNode, XFormsXPathComment>;
|
|
21
25
|
|
|
22
26
|
// prettier-ignore
|
|
23
27
|
export type PrimaryInstanceXPathChildNode =
|
|
24
28
|
// eslint-disable-next-line @typescript-eslint/sort-type-constituents
|
|
25
29
|
| PrimaryInstanceXPathElement
|
|
30
|
+
| PrimaryInstanceXPathAttribute
|
|
26
31
|
| PrimaryInstanceXPathComment;
|
|
27
32
|
|
|
28
33
|
// prettier-ignore
|
|
@@ -41,7 +46,7 @@ export type EngineXPathComment =
|
|
|
41
46
|
|
|
42
47
|
// Giving this a type alias anticipates eventually implementing attributes
|
|
43
48
|
// in primary instance state as well
|
|
44
|
-
export type EngineXPathAttribute = StaticAttribute;
|
|
49
|
+
export type EngineXPathAttribute = PrimaryInstanceXPathAttribute | StaticAttribute;
|
|
45
50
|
|
|
46
51
|
export type EngineXPathText = StaticText;
|
|
47
52
|
|
|
@@ -8,7 +8,6 @@ import type {
|
|
|
8
8
|
EngineXPathDocument,
|
|
9
9
|
EngineXPathElement,
|
|
10
10
|
EngineXPathNode,
|
|
11
|
-
EngineXPathParentNode,
|
|
12
11
|
PrimaryInstanceXPathChildNode,
|
|
13
12
|
XFormsXPathChildNode,
|
|
14
13
|
} from './kind.ts';
|
|
@@ -18,13 +17,13 @@ export const getContainingEngineXPathDocument = (node: EngineXPathNode): EngineX
|
|
|
18
17
|
return node.rootDocument;
|
|
19
18
|
};
|
|
20
19
|
|
|
21
|
-
export const
|
|
22
|
-
node: EngineXPathNode
|
|
23
|
-
): readonly EngineXPathAttribute[] => {
|
|
20
|
+
export const getAttributes = (node: EngineXPathNode): readonly EngineXPathAttribute[] => {
|
|
24
21
|
if (node.nodeType === 'static-element') {
|
|
25
22
|
return node.attributes;
|
|
26
23
|
}
|
|
27
|
-
|
|
24
|
+
if (isEngineXPathElement(node)) {
|
|
25
|
+
return node.getAttributes();
|
|
26
|
+
}
|
|
28
27
|
return [];
|
|
29
28
|
};
|
|
30
29
|
|
|
@@ -43,7 +42,7 @@ export const getEngineXPathAttributes = (
|
|
|
43
42
|
*/
|
|
44
43
|
export const getNamespaceDeclarations = (): readonly [] => [];
|
|
45
44
|
|
|
46
|
-
export const getParentNode = (node: EngineXPathNode):
|
|
45
|
+
export const getParentNode = (node: EngineXPathNode): EngineXPathNode | null => {
|
|
47
46
|
if (node.nodeType === 'repeat-instance') {
|
|
48
47
|
return node.parent.parent;
|
|
49
48
|
}
|
|
@@ -199,6 +199,32 @@ const createCalculation = (
|
|
|
199
199
|
});
|
|
200
200
|
};
|
|
201
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Runs the computation without maintaining a reactive listener, so
|
|
204
|
+
* actions that should run only at a specific time are not triggered
|
|
205
|
+
* when referenced elements are updated.
|
|
206
|
+
*/
|
|
207
|
+
const createActionCalculation = (
|
|
208
|
+
context: ValueContext,
|
|
209
|
+
setRelevantValue: SimpleAtomicStateSetter<string>,
|
|
210
|
+
computation: ActionComputationExpression<'string'>
|
|
211
|
+
): void => {
|
|
212
|
+
createComputed(() => {
|
|
213
|
+
if (context.isAttached()) {
|
|
214
|
+
// use untrack so the expression evaluation isn't reactive
|
|
215
|
+
const relevant = untrack(() => context.isRelevant());
|
|
216
|
+
if (!relevant) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const calculated = untrack(() => {
|
|
220
|
+
return context.evaluator.evaluateString(computation.expression, context);
|
|
221
|
+
});
|
|
222
|
+
const value = context.decodeInstanceValue(calculated);
|
|
223
|
+
setRelevantValue(value);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
|
|
202
228
|
const createValueChangedCalculation = (
|
|
203
229
|
context: ValueContext,
|
|
204
230
|
setRelevantValue: SimpleAtomicStateSetter<string>,
|
|
@@ -235,17 +261,17 @@ const registerAction = (
|
|
|
235
261
|
) => {
|
|
236
262
|
if (action.events.includes(XFORM_EVENT.odkInstanceFirstLoad)) {
|
|
237
263
|
if (isInstanceFirstLoad(context)) {
|
|
238
|
-
|
|
264
|
+
createActionCalculation(context, setValue, action.computation);
|
|
239
265
|
}
|
|
240
266
|
}
|
|
241
267
|
if (action.events.includes(XFORM_EVENT.odkInstanceLoad)) {
|
|
242
268
|
if (!isAddingRepeatChild(context)) {
|
|
243
|
-
|
|
269
|
+
createActionCalculation(context, setValue, action.computation);
|
|
244
270
|
}
|
|
245
271
|
}
|
|
246
272
|
if (action.events.includes(XFORM_EVENT.odkNewRepeat)) {
|
|
247
273
|
if (isAddingRepeatChild(context)) {
|
|
248
|
-
|
|
274
|
+
createActionCalculation(context, setValue, action.computation);
|
|
249
275
|
}
|
|
250
276
|
}
|
|
251
277
|
if (action.events.includes(XFORM_EVENT.xformsValueChanged)) {
|
|
@@ -19,6 +19,7 @@ export class AttributeDefinition
|
|
|
19
19
|
|
|
20
20
|
readonly value: string;
|
|
21
21
|
readonly type = 'attribute';
|
|
22
|
+
readonly valueType = 'string';
|
|
22
23
|
readonly namespaceDeclarations: NamespaceDeclarationMap;
|
|
23
24
|
readonly bodyElement = null;
|
|
24
25
|
readonly root: RootDefinition;
|
|
@@ -56,4 +57,10 @@ export class AttributeDefinition
|
|
|
56
57
|
serializeAttributeXML(): string {
|
|
57
58
|
return this.serializedXML;
|
|
58
59
|
}
|
|
60
|
+
|
|
61
|
+
toJSON() {
|
|
62
|
+
const { bind, bodyElement, parent, root, ...rest } = this;
|
|
63
|
+
|
|
64
|
+
return rest;
|
|
65
|
+
}
|
|
59
66
|
}
|