@getodk/xforms-engine 0.16.0 → 0.17.0
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/client/InputNode.d.ts +8 -4
- package/dist/client/MarkdownNode.d.ts +3 -0
- package/dist/client/NoteNode.d.ts +6 -2
- package/dist/client/form/FormInstanceConfig.d.ts +4 -0
- package/dist/client/form/LoadFormResult.d.ts +5 -14
- package/dist/client/form/ResetFormInstance.d.ts +13 -0
- package/dist/entrypoints/FormResult/BaseFormResult.d.ts +1 -0
- package/dist/entrypoints/FormResult/BaseInstantiableFormResult.d.ts +2 -0
- package/dist/entrypoints/FormResult/FormFailureResult.d.ts +2 -0
- package/dist/entrypoints/createPotentiallyClientOwnedReactiveScope.d.ts +19 -0
- package/dist/index.js +22150 -25908
- 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 +7 -1
- 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/internal-api/AttributeContext.d.ts +1 -0
- package/dist/instance/internal-api/InstanceConfig.d.ts +2 -1
- package/dist/instance/internal-api/InstanceValueContext.d.ts +1 -0
- package/dist/instance/markdown/MarkdownNode.d.ts +14 -9
- 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/integration/xpath/static-dom/StaticDocument.d.ts +2 -0
- package/dist/lib/codecs/{Geopoint/Geopoint.d.ts → geolocation/Geolocation.d.ts} +11 -15
- package/dist/lib/codecs/geolocation/Geopoint.d.ts +7 -0
- package/dist/lib/codecs/geolocation/Geoshape.d.ts +7 -0
- package/dist/lib/codecs/geolocation/Geotrace.d.ts +7 -0
- package/dist/lib/codecs/geolocation/createGeolocationValueCodec.d.ts +3 -0
- package/dist/lib/codecs/getSharedValueCodec.d.ts +7 -5
- package/dist/lib/reactivity/text/createTextRange.d.ts +0 -2
- package/dist/parse/XFormDOM.d.ts +7 -1
- package/dist/parse/body/appearance/inputAppearanceParser.d.ts +1 -1
- package/dist/parse/model/ActionDefinition.d.ts +1 -1
- package/dist/parse/model/AttributeDefinition.d.ts +2 -0
- package/dist/parse/model/BindPreloadDefinition.d.ts +2 -1
- package/dist/parse/model/ModelActionMap.d.ts +3 -2
- package/dist/parse/model/ModelDefinition.d.ts +3 -5
- package/dist/parse/model/SecondaryInstance/sources/CSVExternalSecondaryInstance.d.ts +0 -17
- package/dist/parse/model/SecondaryInstance/sources/external-instance-csv-parser.d.ts +8 -0
- package/dist/parse/model/TranslationDefinitionMap.d.ts +4 -0
- package/dist/solid.js +21608 -25366
- package/dist/solid.js.map +1 -1
- package/package.json +2 -2
- package/src/client/AttributeNode.ts +4 -3
- package/src/client/InputNode.ts +11 -3
- package/src/client/MarkdownNode.ts +3 -0
- package/src/client/NoteNode.ts +9 -1
- package/src/client/form/FormInstanceConfig.ts +6 -0
- package/src/client/form/LoadFormResult.ts +5 -17
- package/src/client/form/ResetFormInstance.ts +17 -0
- package/src/entrypoints/FormInstance.ts +2 -0
- package/src/entrypoints/FormResult/BaseFormResult.ts +1 -0
- package/src/entrypoints/FormResult/BaseInstantiableFormResult.ts +10 -1
- package/src/entrypoints/FormResult/FormFailureResult.ts +3 -0
- package/src/entrypoints/createPotentiallyClientOwnedReactiveScope.ts +30 -0
- package/src/entrypoints/loadForm.ts +1 -31
- package/src/instance/Attribute.ts +38 -54
- package/src/instance/Group.ts +12 -4
- package/src/instance/InputControl.ts +15 -9
- package/src/instance/ModelValue.ts +13 -4
- package/src/instance/Note.ts +13 -4
- package/src/instance/PrimaryInstance.ts +29 -6
- 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 +26 -2
- package/src/instance/children/childrenInitOptions.ts +2 -1
- package/src/instance/hierarchy.ts +2 -0
- package/src/instance/internal-api/AttributeContext.ts +1 -0
- package/src/instance/internal-api/InstanceConfig.ts +3 -0
- package/src/instance/internal-api/InstanceValueContext.ts +1 -0
- package/src/instance/markdown/MarkdownNode.ts +19 -7
- package/src/instance/repeat/RepeatInstance.ts +11 -3
- package/src/instance/text/markdownFormat.ts +4 -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/integration/xpath/static-dom/StaticDocument.ts +2 -0
- package/src/lib/codecs/{Geopoint/Geopoint.ts → geolocation/Geolocation.ts} +43 -24
- package/src/lib/codecs/geolocation/Geopoint.ts +15 -0
- package/src/lib/codecs/geolocation/Geoshape.ts +36 -0
- package/src/lib/codecs/geolocation/Geotrace.ts +36 -0
- package/src/lib/codecs/geolocation/createGeolocationValueCodec.ts +18 -0
- package/src/lib/codecs/getSharedValueCodec.ts +37 -11
- package/src/lib/reactivity/createInstanceValueState.ts +90 -34
- package/src/lib/reactivity/text/createTextRange.ts +71 -45
- package/src/parse/XFormDOM.ts +22 -2
- package/src/parse/model/ActionDefinition.ts +6 -6
- package/src/parse/model/AttributeDefinition.ts +7 -0
- package/src/parse/model/BindDefinition.ts +1 -1
- package/src/parse/model/BindPreloadDefinition.ts +21 -14
- package/src/parse/model/ModelActionMap.ts +30 -13
- package/src/parse/model/ModelDefinition.ts +5 -10
- package/src/parse/model/RootDefinition.ts +2 -1
- package/src/parse/model/SecondaryInstance/sources/CSVExternalSecondaryInstance.ts +2 -184
- package/src/parse/model/SecondaryInstance/sources/external-instance-csv-parser.ts +185 -0
- package/src/parse/model/TranslationDefinitionMap.ts +23 -0
- package/dist/lib/codecs/Geopoint/GeopointValueCodec.d.ts +0 -5
- package/dist/parse/model/generateItextChunks.d.ts +0 -5
- package/src/lib/codecs/Geopoint/GeopointValueCodec.ts +0 -20
- package/src/parse/model/generateItextChunks.ts +0 -61
|
@@ -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
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { StaticAttribute } from '../../integration/xpath/static-dom/StaticAttribute.ts';
|
|
2
|
+
import type { StaticDocument } from '../../integration/xpath/static-dom/StaticDocument.ts';
|
|
3
|
+
import type { StaticElement } from '../../integration/xpath/static-dom/StaticElement.ts';
|
|
1
4
|
import { Attribute } from '../Attribute';
|
|
2
5
|
import type { AnyNode } from '../hierarchy.ts';
|
|
3
6
|
import type { InputControl } from '../InputControl.ts';
|
|
@@ -5,11 +8,32 @@ import type { ModelValue } from '../ModelValue.ts';
|
|
|
5
8
|
import type { Note } from '../Note.ts';
|
|
6
9
|
import type { RangeControl } from '../RangeControl.ts';
|
|
7
10
|
|
|
11
|
+
function buildInstanceAttributeMap(
|
|
12
|
+
instanceNode: StaticAttribute | StaticDocument | StaticElement | null
|
|
13
|
+
): Map<string, StaticAttribute> {
|
|
14
|
+
const map = new Map<string, StaticAttribute>();
|
|
15
|
+
if (!instanceNode) {
|
|
16
|
+
return map;
|
|
17
|
+
}
|
|
18
|
+
for (const attribute of instanceNode.attributes) {
|
|
19
|
+
map.set(attribute.qualifiedName.getPrefixedName(), attribute);
|
|
20
|
+
}
|
|
21
|
+
return map;
|
|
22
|
+
}
|
|
23
|
+
|
|
8
24
|
export function buildAttributes(
|
|
9
25
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
26
|
owner: AnyNode | InputControl<any> | ModelValue<any> | Note<any> | RangeControl<any>
|
|
11
27
|
): Attribute[] {
|
|
12
|
-
|
|
13
|
-
|
|
28
|
+
const attributes = owner.definition.attributes;
|
|
29
|
+
if (!attributes) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
const instanceAttributes = buildInstanceAttributeMap(owner.instanceNode);
|
|
33
|
+
return Array.from(attributes.values()).map((attributeDefinition) => {
|
|
34
|
+
const instanceNode =
|
|
35
|
+
instanceAttributes.get(attributeDefinition.qualifiedName.getPrefixedName()) ??
|
|
36
|
+
attributeDefinition.template;
|
|
37
|
+
return new Attribute(owner, attributeDefinition, instanceNode);
|
|
14
38
|
});
|
|
15
39
|
}
|
|
@@ -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
|
|
@@ -11,6 +11,7 @@ import type { InstanceConfig } from './InstanceConfig.ts';
|
|
|
11
11
|
export interface InstanceAttributeContextDocument {
|
|
12
12
|
readonly initializationMode: FormInstanceInitializationMode;
|
|
13
13
|
readonly isAttached: Accessor<boolean>;
|
|
14
|
+
getBackgroundGeopoint: Accessor<Promise<string>>;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export type DecodeInstanceValue = (value: string) => string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { InstanceAttachmentFileNameFactory } from '../../client/attachments/InstanceAttachmentsConfig.ts';
|
|
2
2
|
import type {
|
|
3
3
|
FormInstanceConfig,
|
|
4
|
+
GeolocationProvider,
|
|
4
5
|
PreloadProperties,
|
|
5
6
|
} from '../../client/form/FormInstanceConfig.ts';
|
|
6
7
|
import type { OpaqueReactiveObjectFactory } from '../../client/OpaqueReactiveObjectFactory.ts';
|
|
@@ -14,4 +15,6 @@ export interface InstanceConfig {
|
|
|
14
15
|
readonly computeAttachmentName: InstanceAttachmentFileNameFactory;
|
|
15
16
|
|
|
16
17
|
readonly preloadProperties: PreloadProperties;
|
|
18
|
+
|
|
19
|
+
readonly geolocationProvider: GeolocationProvider | undefined;
|
|
17
20
|
}
|
|
@@ -11,6 +11,7 @@ import type { InstanceConfig } from './InstanceConfig.ts';
|
|
|
11
11
|
export interface InstanceValueContextDocument {
|
|
12
12
|
readonly initializationMode: FormInstanceInitializationMode;
|
|
13
13
|
readonly isAttached: Accessor<boolean>;
|
|
14
|
+
getBackgroundGeopoint: Accessor<Promise<string>>;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export type DecodeInstanceValue = (value: string) => string;
|
|
@@ -2,18 +2,26 @@ import {
|
|
|
2
2
|
type AnchorMarkdownNode,
|
|
3
3
|
type ChildMarkdownNode as ClientChildMarkdownNode,
|
|
4
4
|
type HtmlMarkdownNode as ClientHtmlMarkdownNode,
|
|
5
|
+
type MarkdownNode as ClientMarkdownNode,
|
|
5
6
|
type ParentMarkdownNode as ClientParentMarkdownNode,
|
|
6
7
|
type StyledMarkdownNode as ClientStyledMarkdownNode,
|
|
7
8
|
type ElementName,
|
|
8
|
-
type MarkdownNode,
|
|
9
9
|
type MarkdownProperty,
|
|
10
10
|
} from '../../client';
|
|
11
11
|
|
|
12
|
-
abstract class
|
|
12
|
+
abstract class MarkdownNode {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
constructor() {
|
|
15
|
+
this.id = crypto.randomUUID();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
abstract class ParentMarkdownNode extends MarkdownNode implements ClientParentMarkdownNode {
|
|
13
20
|
readonly children;
|
|
14
21
|
readonly role = 'parent';
|
|
15
22
|
abstract elementName: ElementName;
|
|
16
|
-
constructor(children:
|
|
23
|
+
constructor(children: ClientMarkdownNode[]) {
|
|
24
|
+
super();
|
|
17
25
|
this.children = children;
|
|
18
26
|
}
|
|
19
27
|
}
|
|
@@ -69,18 +77,20 @@ export class ListItem extends ParentMarkdownNode {
|
|
|
69
77
|
export class Anchor extends ParentMarkdownNode implements AnchorMarkdownNode {
|
|
70
78
|
readonly elementName = 'a';
|
|
71
79
|
readonly url: string;
|
|
72
|
-
constructor(children:
|
|
80
|
+
constructor(children: ClientMarkdownNode[], url: string) {
|
|
73
81
|
super(children);
|
|
74
82
|
this.url = url;
|
|
75
83
|
}
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
abstract class StyledMarkdownNode implements ClientParentMarkdownNode {
|
|
87
|
+
readonly id: string;
|
|
79
88
|
readonly children;
|
|
80
89
|
readonly role = 'parent';
|
|
81
90
|
abstract elementName: ElementName;
|
|
82
91
|
readonly properties: MarkdownProperty | undefined;
|
|
83
|
-
constructor(children:
|
|
92
|
+
constructor(children: ClientMarkdownNode[], properties: MarkdownProperty | undefined) {
|
|
93
|
+
this.id = crypto.randomUUID();
|
|
84
94
|
this.children = children;
|
|
85
95
|
this.properties = properties;
|
|
86
96
|
}
|
|
@@ -98,18 +108,20 @@ export class Div extends StyledMarkdownNode implements ClientStyledMarkdownNode
|
|
|
98
108
|
readonly elementName = 'div';
|
|
99
109
|
}
|
|
100
110
|
|
|
101
|
-
export class ChildMarkdownNode implements ClientChildMarkdownNode {
|
|
111
|
+
export class ChildMarkdownNode extends MarkdownNode implements ClientChildMarkdownNode {
|
|
102
112
|
readonly role = 'child';
|
|
103
113
|
readonly value: string;
|
|
104
114
|
constructor(value: string) {
|
|
115
|
+
super();
|
|
105
116
|
this.value = value;
|
|
106
117
|
}
|
|
107
118
|
}
|
|
108
119
|
|
|
109
|
-
export class Html implements ClientHtmlMarkdownNode {
|
|
120
|
+
export class Html extends MarkdownNode implements ClientHtmlMarkdownNode {
|
|
110
121
|
readonly role = 'html';
|
|
111
122
|
readonly unsafeHtml: string;
|
|
112
123
|
constructor(unsafeHtml: string) {
|
|
124
|
+
super();
|
|
113
125
|
this.unsafeHtml = unsafeHtml;
|
|
114
126
|
}
|
|
115
127
|
}
|
|
@@ -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
|
}
|
|
@@ -42,7 +42,7 @@ const SUPPORTED_HTML_TAGS = Object.entries(HTML_TAG_MAP).map(([tag, type]) => {
|
|
|
42
42
|
};
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
const outputStrings = new Map<string, string>();
|
|
46
46
|
|
|
47
47
|
function validateStyleProperty(name: string | undefined, value: string | undefined): boolean {
|
|
48
48
|
if (!name || !value) {
|
|
@@ -208,7 +208,8 @@ function toOdkMarkdown(str: string): MarkdownNode[] {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
export function format(chunks: readonly TextChunk[]): MarkdownNode[] {
|
|
211
|
-
outputStrings = new Map<string, string>();
|
|
212
211
|
const str = escapeEditableChunks(chunks);
|
|
213
|
-
|
|
212
|
+
const result = toOdkMarkdown(str);
|
|
213
|
+
outputStrings.clear();
|
|
214
|
+
return result;
|
|
214
215
|
}
|
|
@@ -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
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { XFormsXPathDocument } from '../adapter/XFormsXPathNode.ts';
|
|
2
|
+
import type { StaticAttribute } from './StaticAttribute.ts';
|
|
2
3
|
import type { StaticElementOptions } from './StaticElement.ts';
|
|
3
4
|
import { StaticElement } from './StaticElement.ts';
|
|
4
5
|
import { StaticParentNode } from './StaticParentNode.ts';
|
|
@@ -15,6 +16,7 @@ export class StaticDocument extends StaticParentNode<'document'> implements XFor
|
|
|
15
16
|
readonly nodeset: string;
|
|
16
17
|
readonly children: readonly [root: StaticElement];
|
|
17
18
|
readonly childElements: readonly [root: StaticElement];
|
|
19
|
+
readonly attributes: readonly StaticAttribute[] = [];
|
|
18
20
|
|
|
19
21
|
constructor(options: StaticDocumentOptions) {
|
|
20
22
|
super('document');
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This abstract class defines the minimal behavior for a default geopoint.
|
|
3
|
-
* It can be expanded later to support units (e.g., degrees or meters),
|
|
4
|
-
* which would also serve as documentation to clarify what each value represents.
|
|
5
|
-
*/
|
|
6
1
|
abstract class SemanticValue<Semantic extends string, Value extends number | null> {
|
|
7
2
|
abstract readonly semantic: Semantic;
|
|
8
3
|
|
|
@@ -25,26 +20,21 @@ class Accuracy<Value extends number | null = number> extends SemanticValue<'accu
|
|
|
25
20
|
readonly semantic = 'accuracy';
|
|
26
21
|
}
|
|
27
22
|
|
|
28
|
-
export interface
|
|
23
|
+
export interface LocationPoint {
|
|
29
24
|
readonly latitude: number;
|
|
30
25
|
readonly longitude: number;
|
|
31
26
|
readonly altitude: number | null;
|
|
32
27
|
readonly accuracy: number | null;
|
|
33
28
|
}
|
|
34
29
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// TODO: Add support for GeoJSONValue
|
|
38
|
-
export type GeopointInputValue = GeopointRuntimeValue | string;
|
|
39
|
-
|
|
40
|
-
interface GeopointInternalValue {
|
|
30
|
+
interface GeolocationInternalValue {
|
|
41
31
|
readonly latitude: Latitude;
|
|
42
32
|
readonly longitude: Longitude;
|
|
43
33
|
readonly altitude: Altitude<null> | Altitude<number>;
|
|
44
34
|
readonly accuracy: Accuracy<null> | Accuracy<number>;
|
|
45
35
|
}
|
|
46
36
|
|
|
47
|
-
type
|
|
37
|
+
type LocationPointTuple =
|
|
48
38
|
| readonly [
|
|
49
39
|
latitude: Latitude,
|
|
50
40
|
longitude: Longitude,
|
|
@@ -54,6 +44,8 @@ type GeopointTuple =
|
|
|
54
44
|
| readonly [latitude: Latitude, longitude: Longitude, altitude: Altitude]
|
|
55
45
|
| readonly [latitude: Latitude, longitude: Longitude];
|
|
56
46
|
|
|
47
|
+
export const SEGMENT_SEPARATOR = ';';
|
|
48
|
+
|
|
57
49
|
const DEGREES_MAX = {
|
|
58
50
|
latitude: 90,
|
|
59
51
|
longitude: 180,
|
|
@@ -61,10 +53,10 @@ const DEGREES_MAX = {
|
|
|
61
53
|
|
|
62
54
|
type CoordinateType = keyof typeof DEGREES_MAX;
|
|
63
55
|
|
|
64
|
-
export class
|
|
65
|
-
private readonly internalValue:
|
|
56
|
+
export class Geolocation {
|
|
57
|
+
private readonly internalValue: GeolocationInternalValue;
|
|
66
58
|
|
|
67
|
-
constructor(coordinates:
|
|
59
|
+
constructor(coordinates: LocationPoint) {
|
|
68
60
|
const { latitude, longitude, altitude, accuracy } = coordinates;
|
|
69
61
|
|
|
70
62
|
this.internalValue = {
|
|
@@ -75,7 +67,7 @@ export class Geopoint {
|
|
|
75
67
|
};
|
|
76
68
|
}
|
|
77
69
|
|
|
78
|
-
getTuple():
|
|
70
|
+
getTuple(): LocationPointTuple {
|
|
79
71
|
const { latitude, longitude, altitude, accuracy } = this.internalValue;
|
|
80
72
|
|
|
81
73
|
if (accuracy.value != null) {
|
|
@@ -89,12 +81,16 @@ export class Geopoint {
|
|
|
89
81
|
return [latitude, longitude];
|
|
90
82
|
}
|
|
91
83
|
|
|
92
|
-
getRuntimeValue():
|
|
84
|
+
getRuntimeValue(): LocationPoint | null {
|
|
93
85
|
const { latitude, longitude, altitude, accuracy } = this.internalValue;
|
|
94
86
|
const isLatitude = this.isValidDegrees('latitude', latitude.value);
|
|
95
87
|
const isLongitude = this.isValidDegrees('longitude', longitude.value);
|
|
96
88
|
|
|
97
|
-
if (
|
|
89
|
+
if (
|
|
90
|
+
!isLatitude ||
|
|
91
|
+
!isLongitude ||
|
|
92
|
+
Geolocation.isNullLocation(latitude.value, longitude.value)
|
|
93
|
+
) {
|
|
98
94
|
return null;
|
|
99
95
|
}
|
|
100
96
|
|
|
@@ -118,8 +114,9 @@ export class Geopoint {
|
|
|
118
114
|
return latitude === 0 && longitude === 0;
|
|
119
115
|
}
|
|
120
116
|
|
|
121
|
-
static parseString(value: string):
|
|
122
|
-
|
|
117
|
+
static parseString(value: string): LocationPoint | null {
|
|
118
|
+
value = value.trim();
|
|
119
|
+
if (value === '') {
|
|
123
120
|
return null;
|
|
124
121
|
}
|
|
125
122
|
|
|
@@ -132,12 +129,12 @@ export class Geopoint {
|
|
|
132
129
|
return new this({ latitude, longitude, altitude, accuracy }).getRuntimeValue();
|
|
133
130
|
}
|
|
134
131
|
|
|
135
|
-
static toCoordinatesString(value:
|
|
136
|
-
const decodedValue = typeof value === 'string' ?
|
|
132
|
+
static toCoordinatesString(value: LocationPoint | string | null): string {
|
|
133
|
+
const decodedValue = typeof value === 'string' ? Geolocation.parseString(value) : value;
|
|
137
134
|
|
|
138
135
|
if (
|
|
139
136
|
decodedValue == null ||
|
|
140
|
-
|
|
137
|
+
Geolocation.isNullLocation(decodedValue.latitude, decodedValue.longitude)
|
|
141
138
|
) {
|
|
142
139
|
return '';
|
|
143
140
|
}
|
|
@@ -147,4 +144,26 @@ export class Geopoint {
|
|
|
147
144
|
.map((item) => item.value ?? 0)
|
|
148
145
|
.join(' ');
|
|
149
146
|
}
|
|
147
|
+
|
|
148
|
+
static isClosedShape(points: LocationPoint[]) {
|
|
149
|
+
const firstPoint = points[0];
|
|
150
|
+
const lastPoint = points[points.length - 1];
|
|
151
|
+
return (
|
|
152
|
+
firstPoint?.latitude === lastPoint?.latitude && firstPoint?.longitude === lastPoint?.longitude
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
static getSegments(value: string): string[] | null {
|
|
157
|
+
if (value.trim() === '') {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const parts = value.split(SEGMENT_SEPARATOR);
|
|
162
|
+
// Handles trailing semicolon, which is valid and common in ODK.
|
|
163
|
+
if (parts[parts.length - 1]?.trim() === '') {
|
|
164
|
+
parts.pop();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return parts;
|
|
168
|
+
}
|
|
150
169
|
}
|