@getodk/xforms-engine 0.13.0 → 0.15.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 +53 -0
- package/dist/client/BaseItem.d.ts +6 -0
- package/dist/client/GroupNode.d.ts +4 -4
- package/dist/client/MarkdownNode.d.ts +33 -0
- package/dist/client/RankNode.d.ts +2 -4
- package/dist/client/SelectNode.d.ts +2 -5
- package/dist/client/TextRange.d.ts +2 -2
- package/dist/client/hierarchy.d.ts +1 -2
- package/dist/client/index.d.ts +2 -1
- package/dist/client/node-types.d.ts +2 -2
- package/dist/client/validation.d.ts +7 -1
- package/dist/index.js +10758 -402
- package/dist/index.js.map +1 -1
- package/dist/instance/Attribute.d.ts +58 -0
- package/dist/instance/Group.d.ts +4 -0
- package/dist/instance/PrimaryInstance.d.ts +4 -0
- package/dist/instance/Root.d.ts +4 -0
- package/dist/instance/UploadControl.d.ts +4 -0
- package/dist/instance/abstract/InstanceNode.d.ts +7 -4
- package/dist/instance/abstract/ValueNode.d.ts +1 -0
- package/dist/instance/attachments/buildAttributes.d.ts +3 -0
- package/dist/instance/hierarchy.d.ts +6 -6
- package/dist/instance/internal-api/AttributeContext.d.ts +29 -0
- package/dist/instance/internal-api/serialization/ClientReactiveSerializableAttributeNode.d.ts +16 -0
- package/dist/instance/internal-api/serialization/ClientReactiveSerializableParentNode.d.ts +2 -0
- package/dist/instance/internal-api/serialization/ClientReactiveSerializableTemplatedNode.d.ts +2 -2
- package/dist/instance/markdown/MarkdownNode.d.ts +75 -0
- package/dist/instance/repeat/BaseRepeatRange.d.ts +5 -0
- package/dist/instance/repeat/RepeatInstance.d.ts +4 -2
- package/dist/instance/text/TextChunk.d.ts +0 -1
- package/dist/instance/text/TextRange.d.ts +2 -1
- package/dist/instance/text/markdownFormat.d.ts +3 -0
- package/dist/integration/xpath/adapter/XFormsXPathNode.d.ts +2 -2
- package/dist/lib/client-reactivity/instance-state/createAttributeNodeInstanceState.d.ts +3 -0
- package/dist/lib/client-reactivity/instance-state/createTemplatedNodeInstanceState.d.ts +0 -3
- package/dist/lib/names/NamespaceDeclarationMap.d.ts +1 -1
- package/dist/lib/reactivity/createAttributeState.d.ts +16 -0
- package/dist/lib/reactivity/createAttributeValueState.d.ts +15 -0
- package/dist/lib/reactivity/createItemCollection.d.ts +5 -7
- package/dist/lib/xml-serialization.d.ts +5 -9
- package/dist/parse/XFormDOM.d.ts +1 -1
- package/dist/parse/body/BodyDefinition.d.ts +2 -8
- package/dist/parse/body/GroupElementDefinition.d.ts +22 -0
- package/dist/parse/body/control/ItemsetDefinition.d.ts +3 -0
- package/dist/parse/expression/ItemPropertyExpression.d.ts +6 -0
- package/dist/parse/model/AttributeDefinition.d.ts +22 -0
- package/dist/parse/model/{RootAttributeMap.d.ts → AttributeDefinitionMap.d.ts} +4 -10
- package/dist/parse/model/{SubtreeDefinition.d.ts → GroupDefinition.d.ts} +8 -4
- package/dist/parse/model/LeafNodeDefinition.d.ts +1 -0
- package/dist/parse/model/NodeDefinition.d.ts +13 -9
- package/dist/parse/model/RepeatDefinition.d.ts +5 -2
- package/dist/parse/model/RootDefinition.d.ts +3 -3
- package/dist/parse/text/LabelDefinition.d.ts +4 -5
- package/dist/solid.js +10758 -402
- package/dist/solid.js.map +1 -1
- package/package.json +6 -5
- package/src/client/AttributeNode.ts +62 -0
- package/src/client/BaseItem.ts +7 -0
- package/src/client/GroupNode.ts +4 -10
- package/src/client/MarkdownNode.ts +53 -0
- package/src/client/RankNode.ts +2 -5
- package/src/client/SelectNode.ts +2 -6
- package/src/client/TextRange.ts +2 -2
- package/src/client/hierarchy.ts +0 -2
- package/src/client/index.ts +2 -1
- package/src/client/node-types.ts +1 -1
- package/src/client/validation.ts +9 -1
- package/src/instance/Attribute.ts +164 -0
- package/src/instance/Group.ts +17 -1
- package/src/instance/InputControl.ts +1 -0
- package/src/instance/ModelValue.ts +1 -0
- package/src/instance/Note.ts +1 -0
- package/src/instance/PrimaryInstance.ts +17 -0
- package/src/instance/RangeControl.ts +1 -0
- package/src/instance/RankControl.ts +1 -0
- package/src/instance/Root.ts +16 -0
- package/src/instance/SelectControl.ts +1 -0
- package/src/instance/TriggerControl.ts +1 -0
- package/src/instance/UploadControl.ts +14 -0
- package/src/instance/abstract/DescendantNode.ts +5 -1
- package/src/instance/abstract/InstanceNode.ts +6 -3
- package/src/instance/abstract/ValueNode.ts +1 -0
- package/src/instance/attachments/buildAttributes.ts +8 -0
- package/src/instance/children/buildChildren.ts +1 -17
- package/src/instance/children/normalizeChildInitOptions.ts +44 -59
- package/src/instance/hierarchy.ts +3 -7
- package/src/instance/internal-api/AttributeContext.ts +34 -0
- package/src/instance/internal-api/serialization/ClientReactiveSerializableAttributeNode.ts +19 -0
- package/src/instance/internal-api/serialization/ClientReactiveSerializableParentNode.ts +2 -0
- package/src/instance/internal-api/serialization/ClientReactiveSerializableTemplatedNode.ts +2 -3
- package/src/instance/markdown/MarkdownNode.ts +115 -0
- package/src/instance/repeat/BaseRepeatRange.ts +14 -0
- package/src/instance/repeat/RepeatInstance.ts +14 -5
- package/src/instance/text/TextChunk.ts +0 -5
- package/src/instance/text/TextRange.ts +5 -3
- package/src/instance/text/markdownFormat.ts +214 -0
- package/src/integration/xpath/adapter/XFormsXPathNode.ts +3 -1
- package/src/integration/xpath/adapter/names.ts +0 -1
- package/src/lib/client-reactivity/instance-state/createAttributeNodeInstanceState.ts +16 -0
- package/src/lib/client-reactivity/instance-state/createParentNodeInstanceState.ts +5 -5
- package/src/lib/client-reactivity/instance-state/createRootInstanceState.ts +6 -9
- package/src/lib/client-reactivity/instance-state/createTemplatedNodeInstanceState.ts +5 -15
- package/src/lib/names/NamespaceDeclarationMap.ts +1 -1
- package/src/lib/reactivity/createAttributeState.ts +51 -0
- package/src/lib/reactivity/createAttributeValueState.ts +189 -0
- package/src/lib/reactivity/createItemCollection.ts +25 -9
- package/src/lib/xml-serialization.ts +30 -34
- package/src/parse/body/BodyDefinition.ts +7 -34
- package/src/parse/body/GroupElementDefinition.ts +47 -0
- package/src/parse/body/control/ItemsetDefinition.ts +7 -0
- package/src/parse/expression/ItemPropertyExpression.ts +12 -0
- package/src/parse/model/AttributeDefinition.ts +58 -0
- package/src/parse/model/{RootAttributeMap.ts → AttributeDefinitionMap.ts} +7 -13
- package/src/parse/model/{SubtreeDefinition.ts → GroupDefinition.ts} +12 -8
- package/src/parse/model/LeafNodeDefinition.ts +1 -0
- package/src/parse/model/NodeDefinition.ts +19 -12
- package/src/parse/model/RepeatDefinition.ts +10 -3
- package/src/parse/model/RootDefinition.ts +6 -6
- package/src/parse/model/nodeDefinitionMap.ts +1 -1
- package/src/parse/text/LabelDefinition.ts +4 -9
- package/dist/client/SubtreeNode.d.ts +0 -56
- package/dist/error/TemplatedNodeAttributeSerializationError.d.ts +0 -22
- package/dist/instance/Subtree.d.ts +0 -38
- package/dist/instance/text/FormattedTextStub.d.ts +0 -1
- package/dist/parse/body/group/BaseGroupDefinition.d.ts +0 -40
- package/dist/parse/body/group/LogicalGroupDefinition.d.ts +0 -6
- package/dist/parse/body/group/PresentationGroupDefinition.d.ts +0 -11
- package/dist/parse/body/group/StructuralGroupDefinition.d.ts +0 -6
- package/dist/parse/model/RootAttributeDefinition.d.ts +0 -21
- package/src/client/SubtreeNode.ts +0 -61
- package/src/error/TemplatedNodeAttributeSerializationError.ts +0 -24
- package/src/instance/Subtree.ts +0 -102
- package/src/instance/text/FormattedTextStub.ts +0 -8
- package/src/parse/body/group/BaseGroupDefinition.ts +0 -89
- package/src/parse/body/group/LogicalGroupDefinition.ts +0 -11
- package/src/parse/body/group/PresentationGroupDefinition.ts +0 -28
- package/src/parse/body/group/StructuralGroupDefinition.ts +0 -11
- package/src/parse/model/RootAttributeDefinition.ts +0 -44
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { TemplatedNodeAttributeSerializationError } from '../../../error/TemplatedNodeAttributeSerializationError.ts';
|
|
2
1
|
import type { StaticElement } from '../../../integration/xpath/static-dom/StaticElement.ts';
|
|
2
|
+
import type { Attribute } from '../../Attribute.ts';
|
|
3
3
|
import type { GeneralChildNode } from '../../hierarchy.ts';
|
|
4
4
|
import type {
|
|
5
5
|
ClientReactiveSerializableParentNode,
|
|
@@ -9,8 +9,7 @@ import type {
|
|
|
9
9
|
|
|
10
10
|
export interface ClientReactiveSerializableTemplatedNodeCurrentState
|
|
11
11
|
extends ClientReactiveSerializableParentNodeCurrentState<GeneralChildNode> {
|
|
12
|
-
|
|
13
|
-
get attributes(): unknown;
|
|
12
|
+
get attributes(): readonly Attribute[];
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
export interface ClientReactiveSerializableTemplatedNodeDefinition
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type AnchorMarkdownNode,
|
|
3
|
+
type ChildMarkdownNode as ClientChildMarkdownNode,
|
|
4
|
+
type HtmlMarkdownNode as ClientHtmlMarkdownNode,
|
|
5
|
+
type ParentMarkdownNode as ClientParentMarkdownNode,
|
|
6
|
+
type StyledMarkdownNode as ClientStyledMarkdownNode,
|
|
7
|
+
type ElementName,
|
|
8
|
+
type MarkdownNode,
|
|
9
|
+
type MarkdownProperty,
|
|
10
|
+
} from '../../client';
|
|
11
|
+
|
|
12
|
+
abstract class ParentMarkdownNode implements ClientParentMarkdownNode {
|
|
13
|
+
readonly children;
|
|
14
|
+
readonly role = 'parent';
|
|
15
|
+
abstract elementName: ElementName;
|
|
16
|
+
constructor(children: MarkdownNode[]) {
|
|
17
|
+
this.children = children;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class Heading1 extends ParentMarkdownNode {
|
|
22
|
+
readonly elementName = 'h1';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class Heading2 extends ParentMarkdownNode {
|
|
26
|
+
readonly elementName = 'h2';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export class Heading3 extends ParentMarkdownNode {
|
|
30
|
+
readonly elementName = 'h3';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class Heading4 extends ParentMarkdownNode {
|
|
34
|
+
readonly elementName = 'h4';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export class Heading5 extends ParentMarkdownNode {
|
|
38
|
+
readonly elementName = 'h5';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export class Heading6 extends ParentMarkdownNode {
|
|
42
|
+
readonly elementName = 'h6';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export class Strong extends ParentMarkdownNode {
|
|
46
|
+
readonly elementName = 'strong';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class Underline extends ParentMarkdownNode {
|
|
50
|
+
readonly elementName = 'u';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class Emphasis extends ParentMarkdownNode {
|
|
54
|
+
readonly elementName = 'em';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class OrderedList extends ParentMarkdownNode {
|
|
58
|
+
readonly elementName = 'ol';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export class UnorderedList extends ParentMarkdownNode {
|
|
62
|
+
readonly elementName = 'ul';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export class ListItem extends ParentMarkdownNode {
|
|
66
|
+
readonly elementName = 'li';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export class Anchor extends ParentMarkdownNode implements AnchorMarkdownNode {
|
|
70
|
+
readonly elementName = 'a';
|
|
71
|
+
readonly url: string;
|
|
72
|
+
constructor(children: MarkdownNode[], url: string) {
|
|
73
|
+
super(children);
|
|
74
|
+
this.url = url;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
abstract class StyledMarkdownNode implements ClientParentMarkdownNode {
|
|
79
|
+
readonly children;
|
|
80
|
+
readonly role = 'parent';
|
|
81
|
+
abstract elementName: ElementName;
|
|
82
|
+
readonly properties: MarkdownProperty | undefined;
|
|
83
|
+
constructor(children: MarkdownNode[], properties: MarkdownProperty | undefined) {
|
|
84
|
+
this.children = children;
|
|
85
|
+
this.properties = properties;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export class Paragraph extends StyledMarkdownNode implements ClientStyledMarkdownNode {
|
|
90
|
+
readonly elementName = 'p';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export class Span extends StyledMarkdownNode implements ClientStyledMarkdownNode {
|
|
94
|
+
readonly elementName = 'span';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export class Div extends StyledMarkdownNode implements ClientStyledMarkdownNode {
|
|
98
|
+
readonly elementName = 'div';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export class ChildMarkdownNode implements ClientChildMarkdownNode {
|
|
102
|
+
readonly role = 'child';
|
|
103
|
+
readonly value: string;
|
|
104
|
+
constructor(value: string) {
|
|
105
|
+
this.value = value;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export class Html implements ClientHtmlMarkdownNode {
|
|
110
|
+
readonly role = 'html';
|
|
111
|
+
readonly unsafeHtml: string;
|
|
112
|
+
constructor(unsafeHtml: string) {
|
|
113
|
+
this.unsafeHtml = unsafeHtml;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -17,6 +17,10 @@ import type {
|
|
|
17
17
|
import { XFORMS_XPATH_NODE_RANGE_KIND } from '../../integration/xpath/adapter/XFormsXPathNode.ts';
|
|
18
18
|
import type { StaticElement } from '../../integration/xpath/static-dom/StaticElement.ts';
|
|
19
19
|
import { createNodeRangeInstanceState } from '../../lib/client-reactivity/instance-state/createNodeRangeInstanceState.ts';
|
|
20
|
+
import {
|
|
21
|
+
createAttributeState,
|
|
22
|
+
type AttributeState,
|
|
23
|
+
} from '../../lib/reactivity/createAttributeState.ts';
|
|
20
24
|
import type { ChildrenState } from '../../lib/reactivity/createChildrenState.ts';
|
|
21
25
|
import { createChildrenState } from '../../lib/reactivity/createChildrenState.ts';
|
|
22
26
|
import type { MaterializedChildren } from '../../lib/reactivity/materializeCurrentStateChildren.ts';
|
|
@@ -32,6 +36,7 @@ import type {
|
|
|
32
36
|
DescendantNodeSharedStateSpec,
|
|
33
37
|
} from '../abstract/DescendantNode.ts';
|
|
34
38
|
import { DescendantNode } from '../abstract/DescendantNode.ts';
|
|
39
|
+
import type { Attribute } from '../Attribute.ts';
|
|
35
40
|
import type { GeneralParentNode, RepeatRange } from '../hierarchy.ts';
|
|
36
41
|
import type { EvaluationContext } from '../internal-api/EvaluationContext.ts';
|
|
37
42
|
import type { ClientReactiveSerializableParentNode } from '../internal-api/serialization/ClientReactiveSerializableParentNode.ts';
|
|
@@ -41,6 +46,7 @@ interface RepeatRangeStateSpec extends DescendantNodeSharedStateSpec {
|
|
|
41
46
|
readonly hint: null;
|
|
42
47
|
readonly label: Accessor<TextRange<'label'> | null>;
|
|
43
48
|
readonly children: Accessor<readonly FormNodeID[]>;
|
|
49
|
+
readonly attributes: Accessor<readonly Attribute[]>;
|
|
44
50
|
readonly valueOptions: null;
|
|
45
51
|
readonly value: null;
|
|
46
52
|
}
|
|
@@ -60,6 +66,7 @@ export abstract class BaseRepeatRange<Definition extends AnyRepeatDefinition>
|
|
|
60
66
|
ClientReactiveSerializableParentNode<RepeatInstance>
|
|
61
67
|
{
|
|
62
68
|
protected readonly childrenState: ChildrenState<RepeatInstance>;
|
|
69
|
+
protected readonly attributeState: AttributeState;
|
|
63
70
|
|
|
64
71
|
/**
|
|
65
72
|
* A repeat range doesn't have a corresponding primary instance element of its
|
|
@@ -156,8 +163,10 @@ export abstract class BaseRepeatRange<Definition extends AnyRepeatDefinition>
|
|
|
156
163
|
const repeatRange = this as AnyDescendantNode as RepeatRange;
|
|
157
164
|
|
|
158
165
|
const childrenState = createChildrenState<RepeatRange, RepeatInstance>(repeatRange);
|
|
166
|
+
const attributeState = createAttributeState(this.scope);
|
|
159
167
|
|
|
160
168
|
this.childrenState = childrenState;
|
|
169
|
+
this.attributeState = attributeState;
|
|
161
170
|
|
|
162
171
|
const state = createSharedNodeState(
|
|
163
172
|
this.scope,
|
|
@@ -170,6 +179,7 @@ export abstract class BaseRepeatRange<Definition extends AnyRepeatDefinition>
|
|
|
170
179
|
label: createNodeLabel(this, definition),
|
|
171
180
|
hint: null,
|
|
172
181
|
children: childrenState.childIds,
|
|
182
|
+
attributes: attributeState.getAttributes,
|
|
173
183
|
valueOptions: null,
|
|
174
184
|
value: null,
|
|
175
185
|
},
|
|
@@ -260,4 +270,8 @@ export abstract class BaseRepeatRange<Definition extends AnyRepeatDefinition>
|
|
|
260
270
|
getChildren(): readonly RepeatInstance[] {
|
|
261
271
|
return this.childrenState.getChildren();
|
|
262
272
|
}
|
|
273
|
+
|
|
274
|
+
getAttributes(): readonly Attribute[] {
|
|
275
|
+
return this.attributeState.getAttributes();
|
|
276
|
+
}
|
|
263
277
|
}
|
|
@@ -10,10 +10,13 @@ import type {
|
|
|
10
10
|
import type { InstanceState } from '../../client/serialization/InstanceState.ts';
|
|
11
11
|
import type { TextRange } from '../../client/TextRange.ts';
|
|
12
12
|
import type { AncestorNodeValidationState } from '../../client/validation.ts';
|
|
13
|
-
import type { TemplatedNodeAttributeSerializationError } from '../../error/TemplatedNodeAttributeSerializationError.ts';
|
|
14
13
|
import type { XFormsXPathElement } from '../../integration/xpath/adapter/XFormsXPathNode.ts';
|
|
15
14
|
import type { StaticElement } from '../../integration/xpath/static-dom/StaticElement.ts';
|
|
16
15
|
import { createTemplatedNodeInstanceState } from '../../lib/client-reactivity/instance-state/createTemplatedNodeInstanceState.ts';
|
|
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';
|
|
@@ -26,6 +29,7 @@ import { createNodeLabel } from '../../lib/reactivity/text/createNodeLabel.ts';
|
|
|
26
29
|
import { createAggregatedViolations } from '../../lib/reactivity/validation/createAggregatedViolations.ts';
|
|
27
30
|
import type { DescendantNodeSharedStateSpec } from '../abstract/DescendantNode.ts';
|
|
28
31
|
import { DescendantNode } from '../abstract/DescendantNode.ts';
|
|
32
|
+
import type { Attribute } from '../Attribute.ts';
|
|
29
33
|
import { buildChildren } from '../children/buildChildren.ts';
|
|
30
34
|
import type { GeneralChildNode, RepeatRange } from '../hierarchy.ts';
|
|
31
35
|
import type { EvaluationContext } from '../internal-api/EvaluationContext.ts';
|
|
@@ -35,9 +39,7 @@ interface RepeatInstanceStateSpec extends DescendantNodeSharedStateSpec {
|
|
|
35
39
|
readonly label: Accessor<TextRange<'label'> | null>;
|
|
36
40
|
readonly hint: null;
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
readonly attributes: null;
|
|
40
|
-
|
|
42
|
+
readonly attributes: Accessor<readonly Attribute[]>;
|
|
41
43
|
readonly children: Accessor<readonly FormNodeID[]>;
|
|
42
44
|
readonly valueOptions: null;
|
|
43
45
|
readonly value: null;
|
|
@@ -61,6 +63,7 @@ export class RepeatInstance
|
|
|
61
63
|
ClientReactiveSerializableTemplatedNode
|
|
62
64
|
{
|
|
63
65
|
private readonly childrenState: ChildrenState<GeneralChildNode>;
|
|
66
|
+
private readonly attributeState: AttributeState;
|
|
64
67
|
private readonly currentIndex: Accessor<number>;
|
|
65
68
|
|
|
66
69
|
override readonly [XPathNodeKindKey] = 'element';
|
|
@@ -132,8 +135,10 @@ export class RepeatInstance
|
|
|
132
135
|
this.appearances = definition.bodyElement.appearances;
|
|
133
136
|
|
|
134
137
|
const childrenState = createChildrenState<RepeatInstance, GeneralChildNode>(this);
|
|
138
|
+
const attributeState = createAttributeState(this.scope);
|
|
135
139
|
|
|
136
140
|
this.childrenState = childrenState;
|
|
141
|
+
this.attributeState = attributeState;
|
|
137
142
|
this.currentIndex = currentIndex;
|
|
138
143
|
|
|
139
144
|
const state = createSharedNodeState(
|
|
@@ -147,7 +152,7 @@ export class RepeatInstance
|
|
|
147
152
|
// TODO: only-child <group><label>
|
|
148
153
|
label: createNodeLabel(this, definition),
|
|
149
154
|
hint: null,
|
|
150
|
-
attributes:
|
|
155
|
+
attributes: attributeState.getAttributes,
|
|
151
156
|
children: childrenState.childIds,
|
|
152
157
|
valueOptions: null,
|
|
153
158
|
value: null,
|
|
@@ -192,4 +197,8 @@ export class RepeatInstance
|
|
|
192
197
|
getChildren(): readonly GeneralChildNode[] {
|
|
193
198
|
return this.childrenState.getChildren();
|
|
194
199
|
}
|
|
200
|
+
|
|
201
|
+
getAttributes(): readonly Attribute[] {
|
|
202
|
+
return this.attributeState.getAttributes();
|
|
203
|
+
}
|
|
195
204
|
}
|
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
import type { ActiveLanguage } from '../../client/FormLanguage.ts';
|
|
2
2
|
import type { TextChunk as ClientTextChunk, TextChunkSource } from '../../client/TextRange.ts';
|
|
3
3
|
import type { TranslationContext } from '../internal-api/TranslationContext.ts';
|
|
4
|
-
import { FormattedTextStub } from './FormattedTextStub.ts';
|
|
5
4
|
|
|
6
5
|
export class TextChunk implements ClientTextChunk {
|
|
7
|
-
get formatted() {
|
|
8
|
-
return FormattedTextStub;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
6
|
get language(): ActiveLanguage {
|
|
12
7
|
return this.context.getActiveLanguage();
|
|
13
8
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { JRResourceURL } from '@getodk/common/jr-resources/JRResourceURL.ts';
|
|
2
|
+
|
|
3
|
+
import type { MarkdownNode } from '../../client/MarkdownNode.ts';
|
|
2
4
|
import type {
|
|
3
5
|
TextRange as ClientTextRange,
|
|
4
6
|
TextChunk,
|
|
5
7
|
TextOrigin,
|
|
6
8
|
TextRole,
|
|
7
9
|
} from '../../client/TextRange.ts';
|
|
8
|
-
import {
|
|
10
|
+
import { format } from './markdownFormat.ts';
|
|
9
11
|
|
|
10
12
|
export interface MediaSources {
|
|
11
13
|
image?: JRResourceURL;
|
|
@@ -20,8 +22,8 @@ export class TextRange<Role extends TextRole, Origin extends TextOrigin>
|
|
|
20
22
|
yield* this.chunks;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
get formatted() {
|
|
24
|
-
return
|
|
25
|
+
get formatted(): MarkdownNode[] {
|
|
26
|
+
return format(this.chunks);
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
get asString(): string {
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import type { Heading, Literal, RootContent } from 'mdast';
|
|
2
|
+
import { fromMarkdown } from 'mdast-util-from-markdown';
|
|
3
|
+
import { type MarkdownNode, type StyleProperty } from '../../client';
|
|
4
|
+
import type { TextChunk } from '../../client/TextRange.ts';
|
|
5
|
+
import {
|
|
6
|
+
Anchor,
|
|
7
|
+
ChildMarkdownNode,
|
|
8
|
+
Div,
|
|
9
|
+
Emphasis,
|
|
10
|
+
Heading1,
|
|
11
|
+
Heading2,
|
|
12
|
+
Heading3,
|
|
13
|
+
Heading4,
|
|
14
|
+
Heading5,
|
|
15
|
+
Heading6,
|
|
16
|
+
Html,
|
|
17
|
+
ListItem,
|
|
18
|
+
OrderedList,
|
|
19
|
+
Paragraph,
|
|
20
|
+
Span,
|
|
21
|
+
Strong,
|
|
22
|
+
Underline,
|
|
23
|
+
UnorderedList,
|
|
24
|
+
} from '../markdown/MarkdownNode.ts';
|
|
25
|
+
|
|
26
|
+
const STYLE_PROPERTY_REGEX = /style\s*=\s*(?:'|")(.+)(?:'|")/i;
|
|
27
|
+
const HTML_TAG_MAP = {
|
|
28
|
+
span: Span,
|
|
29
|
+
div: Div,
|
|
30
|
+
p: Paragraph,
|
|
31
|
+
u: Underline,
|
|
32
|
+
i: Emphasis,
|
|
33
|
+
em: Emphasis,
|
|
34
|
+
b: Strong,
|
|
35
|
+
strong: Strong,
|
|
36
|
+
};
|
|
37
|
+
const SUPPORTED_HTML_TAGS = Object.entries(HTML_TAG_MAP).map(([tag, type]) => {
|
|
38
|
+
return {
|
|
39
|
+
openRegex: RegExp(`^\\s*<\\s*${tag}[\\s+>]`, 'i'),
|
|
40
|
+
closeRegex: RegExp(`<\\s*/${tag}\\s*>`, 'i'),
|
|
41
|
+
type,
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
let outputStrings: Map<string, string>;
|
|
46
|
+
|
|
47
|
+
function validateStyleProperty(name: string | undefined, value: string | undefined): boolean {
|
|
48
|
+
if (!name || !value) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
if (!['color', 'font-family', 'text-align', 'font-size'].includes(name)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
if (name === 'text-align' && !['left', 'right', 'center'].includes(value)) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function parseStyle(tag: string): StyleProperty | undefined {
|
|
61
|
+
const styleProperty = STYLE_PROPERTY_REGEX.exec(tag);
|
|
62
|
+
if (!styleProperty || styleProperty.length < 2) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const styleValue = styleProperty[1] ?? '';
|
|
66
|
+
const properties = styleValue.split(';');
|
|
67
|
+
const entries: string[][] = [];
|
|
68
|
+
properties.forEach((property) => {
|
|
69
|
+
const [name, value] = property.split(':').map((val) => val.trim());
|
|
70
|
+
if (validateStyleProperty(name, value)) {
|
|
71
|
+
entries.push([name!, value!]);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
if (!entries.length) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
return Object.fromEntries(entries) as StyleProperty;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function mdastHeading(tree: Heading, children: MarkdownNode[]): MarkdownNode {
|
|
81
|
+
if (tree.depth === 1) {
|
|
82
|
+
return new Heading1(children);
|
|
83
|
+
}
|
|
84
|
+
if (tree.depth === 2) {
|
|
85
|
+
return new Heading2(children);
|
|
86
|
+
}
|
|
87
|
+
if (tree.depth === 3) {
|
|
88
|
+
return new Heading3(children);
|
|
89
|
+
}
|
|
90
|
+
if (tree.depth === 4) {
|
|
91
|
+
return new Heading4(children);
|
|
92
|
+
}
|
|
93
|
+
if (tree.depth === 5) {
|
|
94
|
+
return new Heading5(children);
|
|
95
|
+
}
|
|
96
|
+
return new Heading6(children);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function mdastNodeToOdkMarkdown(tree: RootContent): MarkdownNode | undefined {
|
|
100
|
+
if (tree.type === 'html') {
|
|
101
|
+
return new Html(tree.value);
|
|
102
|
+
}
|
|
103
|
+
if (tree.type === 'text' || tree.type === 'inlineCode') {
|
|
104
|
+
const outputString = outputStrings.get(tree.value);
|
|
105
|
+
if (outputString) {
|
|
106
|
+
const children = toOdkMarkdown(outputString);
|
|
107
|
+
return new Span(children, undefined);
|
|
108
|
+
}
|
|
109
|
+
return new ChildMarkdownNode(tree.value);
|
|
110
|
+
}
|
|
111
|
+
if ('children' in tree) {
|
|
112
|
+
const children = mdastToOdkMarkdown(tree.children);
|
|
113
|
+
if (tree.type === 'paragraph') {
|
|
114
|
+
return new Paragraph(children, undefined);
|
|
115
|
+
}
|
|
116
|
+
if (tree.type === 'strong') {
|
|
117
|
+
return new Strong(children);
|
|
118
|
+
}
|
|
119
|
+
if (tree.type === 'emphasis') {
|
|
120
|
+
return new Emphasis(children);
|
|
121
|
+
}
|
|
122
|
+
if (tree.type === 'link') {
|
|
123
|
+
return new Anchor(children, tree.url);
|
|
124
|
+
}
|
|
125
|
+
if (tree.type === 'list') {
|
|
126
|
+
if (tree.ordered) {
|
|
127
|
+
return new OrderedList(children);
|
|
128
|
+
} else {
|
|
129
|
+
return new UnorderedList(children);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (tree.type === 'listItem') {
|
|
133
|
+
return new ListItem(children);
|
|
134
|
+
}
|
|
135
|
+
if (tree.type === 'heading') {
|
|
136
|
+
return mdastHeading(tree, children);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function getUnclosedHtmlTag(tree: RootContent) {
|
|
143
|
+
if (tree.type !== 'html') {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const tag = SUPPORTED_HTML_TAGS.find((supported) => supported.openRegex.test(tree.value));
|
|
147
|
+
if (!tag || tag.closeRegex.test(tree.value)) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
return tag;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function mdastToOdkMarkdown(elements: RootContent[]): MarkdownNode[] {
|
|
154
|
+
const result: MarkdownNode[] = [];
|
|
155
|
+
for (let i = 0; i < elements.length; i++) {
|
|
156
|
+
const tree = elements[i]!;
|
|
157
|
+
const tag = getUnclosedHtmlTag(tree);
|
|
158
|
+
if (!tag) {
|
|
159
|
+
const odkMarkdown = mdastNodeToOdkMarkdown(tree);
|
|
160
|
+
if (odkMarkdown) {
|
|
161
|
+
result.push(odkMarkdown);
|
|
162
|
+
}
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// SPECIAL CASE in mdast processing
|
|
167
|
+
// span children are parsed into siblings in the mdast for some reason
|
|
168
|
+
// so we need to advance `i` as we consume siblings
|
|
169
|
+
const children: RootContent[] = [];
|
|
170
|
+
let next = elements[++i];
|
|
171
|
+
while (next && !(next.type === 'html' && tag.closeRegex.test(next.value))) {
|
|
172
|
+
children.push(next);
|
|
173
|
+
next = elements[++i];
|
|
174
|
+
}
|
|
175
|
+
const odkChildren = mdastToOdkMarkdown(children);
|
|
176
|
+
const style = parseStyle((tree as Literal).value);
|
|
177
|
+
const properties = style && { style };
|
|
178
|
+
result.push(new tag.type(odkChildren, properties));
|
|
179
|
+
}
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function escapeEditableChunks(chunks: readonly TextChunk[]) {
|
|
184
|
+
return chunks
|
|
185
|
+
.map((chunk, i) => {
|
|
186
|
+
const str = chunk.asString;
|
|
187
|
+
if (str && chunk.source === 'output') {
|
|
188
|
+
// we need to process this separately otherwise user entered markup will
|
|
189
|
+
// interract with form markup in unexpected ways
|
|
190
|
+
const id = `--ODK-OUTPUT-STRING-${i}--`;
|
|
191
|
+
outputStrings.set(id, str);
|
|
192
|
+
return '`' + id + '`';
|
|
193
|
+
}
|
|
194
|
+
return str ?? '';
|
|
195
|
+
})
|
|
196
|
+
.join('');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function toOdkMarkdown(str: string): MarkdownNode[] {
|
|
200
|
+
const tree = fromMarkdown(str);
|
|
201
|
+
const odk = mdastToOdkMarkdown(tree.children);
|
|
202
|
+
if (odk.length === 1 && odk[0]?.role === 'parent' && odk[0]?.elementName === 'p') {
|
|
203
|
+
// mdast tends to add too many paragraphs which if left in place, puts a block level
|
|
204
|
+
// element where it's not needed
|
|
205
|
+
return odk[0].children;
|
|
206
|
+
}
|
|
207
|
+
return odk;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function format(chunks: readonly TextChunk[]): MarkdownNode[] {
|
|
211
|
+
outputStrings = new Map<string, string>();
|
|
212
|
+
const str = escapeEditableChunks(chunks);
|
|
213
|
+
return toOdkMarkdown(str);
|
|
214
|
+
}
|
|
@@ -97,7 +97,8 @@ export type XFormsXPathDescendantNodeKind =
|
|
|
97
97
|
| XFormsXPathNodeRangeKind
|
|
98
98
|
| XPathElementKind
|
|
99
99
|
| XPathTextKind
|
|
100
|
-
| XPathCommentKind
|
|
100
|
+
| XPathCommentKind
|
|
101
|
+
| XPathAttributeKind;
|
|
101
102
|
|
|
102
103
|
export interface XFormsXPathDescendantNode extends XFormsXPathNode {
|
|
103
104
|
readonly [XPathNodeKindKey]: XFormsXPathDescendantNodeKind;
|
|
@@ -109,6 +110,7 @@ export type XFormsXPathPrimaryInstanceNodeKind =
|
|
|
109
110
|
| XPathDocumentKind
|
|
110
111
|
| XFormsXPathNodeRangeKind
|
|
111
112
|
| XPathElementKind
|
|
113
|
+
| XPathAttributeKind
|
|
112
114
|
| XPathTextKind;
|
|
113
115
|
|
|
114
116
|
export interface XFormsXPathPrimaryInstanceNode extends XFormsXPathNode {
|
|
@@ -140,7 +140,6 @@ export const resolveEngineXPathNodeNamespaceURI = (
|
|
|
140
140
|
case 'repeat-range:uncontrolled':
|
|
141
141
|
case 'root':
|
|
142
142
|
case 'select':
|
|
143
|
-
case 'subtree':
|
|
144
143
|
case 'trigger':
|
|
145
144
|
case 'upload':
|
|
146
145
|
return node.definition.namespaceDeclarations.get(prefix)?.declaredURI?.href ?? null;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { InstanceState } from '../../../client/serialization/InstanceState.ts';
|
|
2
|
+
import type { ClientReactiveSerializableAttributeNode } from '../../../instance/internal-api/serialization/ClientReactiveSerializableAttributeNode.ts';
|
|
3
|
+
import { escapeXMLText, serializeAttributeXML } from '../../xml-serialization.ts';
|
|
4
|
+
|
|
5
|
+
export const createAttributeNodeInstanceState = (
|
|
6
|
+
node: ClientReactiveSerializableAttributeNode
|
|
7
|
+
): InstanceState => {
|
|
8
|
+
const { qualifiedName } = node.definition;
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
get instanceXML() {
|
|
12
|
+
const xmlValue = escapeXMLText(node.currentState.instanceValue, true);
|
|
13
|
+
return serializeAttributeXML(qualifiedName, xmlValue);
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
};
|
|
@@ -12,11 +12,11 @@ export const createParentNodeInstanceState = (
|
|
|
12
12
|
return '';
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
return serializeParentElementXML(
|
|
16
|
+
node.definition.qualifiedName,
|
|
17
|
+
node.currentState.children,
|
|
18
|
+
node.currentState.attributes
|
|
19
|
+
);
|
|
20
20
|
},
|
|
21
21
|
};
|
|
22
22
|
};
|
|
@@ -5,15 +5,12 @@ import { serializeParentElementXML } from '../../xml-serialization.ts';
|
|
|
5
5
|
export const createRootInstanceState = (node: Root): InstanceState => {
|
|
6
6
|
return {
|
|
7
7
|
get instanceXML() {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
namespaceDeclarations,
|
|
15
|
-
attributes: Array.from(attributes.values()),
|
|
16
|
-
});
|
|
8
|
+
return serializeParentElementXML(
|
|
9
|
+
node.definition.qualifiedName,
|
|
10
|
+
node.currentState.children,
|
|
11
|
+
node.currentState.attributes,
|
|
12
|
+
node.definition.namespaceDeclarations
|
|
13
|
+
);
|
|
17
14
|
},
|
|
18
15
|
};
|
|
19
16
|
};
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import type { InstanceState } from '../../../client/serialization/InstanceState.ts';
|
|
2
|
-
import { TemplatedNodeAttributeSerializationError } from '../../../error/TemplatedNodeAttributeSerializationError.ts';
|
|
3
2
|
import type { ClientReactiveSerializableTemplatedNode } from '../../../instance/internal-api/serialization/ClientReactiveSerializableTemplatedNode.ts';
|
|
4
3
|
import { serializeParentElementXML } from '../../xml-serialization.ts';
|
|
5
4
|
|
|
6
|
-
/**
|
|
7
|
-
* @see {@link TemplatedNodeAttributeSerializationError}
|
|
8
|
-
*/
|
|
9
5
|
export const createTemplatedNodeInstanceState = (
|
|
10
6
|
node: ClientReactiveSerializableTemplatedNode
|
|
11
7
|
): InstanceState => {
|
|
@@ -15,17 +11,11 @@ export const createTemplatedNodeInstanceState = (
|
|
|
15
11
|
return '';
|
|
16
12
|
}
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (attributes != null) {
|
|
25
|
-
throw new TemplatedNodeAttributeSerializationError();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return serializeParentElementXML(node.definition.qualifiedName, serializedChildren);
|
|
14
|
+
return serializeParentElementXML(
|
|
15
|
+
node.definition.qualifiedName,
|
|
16
|
+
node.currentState.children,
|
|
17
|
+
node.currentState.attributes
|
|
18
|
+
);
|
|
29
19
|
},
|
|
30
20
|
};
|
|
31
21
|
};
|
|
@@ -11,7 +11,7 @@ type NamedNodeDefinitionMap = ReadonlyMap<QualifiedName, NamedNodeDefinition>;
|
|
|
11
11
|
export interface NamedSubtreeDefinition extends NamedNodeDefinition {
|
|
12
12
|
readonly namespaceDeclarations: NamespaceDeclarationMap;
|
|
13
13
|
readonly parent: NamedSubtreeDefinition | null;
|
|
14
|
-
readonly attributes
|
|
14
|
+
readonly attributes: NamedNodeDefinitionMap | null;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|