Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pyxform/aliases.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@
"big-image": "media::big-image",
"audio": "media::audio",
"video": "media::video",
"image-description": "media::image-description",
"count": "control::jr:count",
"repeat_count": "control::jr:count",
"jr:count": "control::jr:count",
Expand Down Expand Up @@ -142,6 +143,7 @@
"big-image": "media::big-image",
"audio": "media::audio",
"video": "media::video",
"image-description": "media::image-description",
}
# Note that most of the type aliasing happens in all.xls
_type_alias_map = {
Expand Down
2 changes: 1 addition & 1 deletion pyxform/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,5 +166,5 @@ class EntityColumns(StrEnum):
"xmlns:orx": "http://openrosa.org/xforms",
"xmlns:odk": "http://www.opendatakit.org/xforms",
}
SUPPORTED_MEDIA_TYPES = {"image", "big-image", "audio", "video"}
SUPPORTED_MEDIA_TYPES = {"image", "big-image", "audio", "video", "image-description"}
OR_OTHER_CHOICE = {NAME: "other", LABEL: "Other"}
10 changes: 10 additions & 0 deletions pyxform/json_form_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,16 @@
"type" : "string",
"description" : "A key value pair where the key is a language, and the value is the content uri in that language."
}
},
"image-description" :
{
"type" : ["object", "string"],
"description" : "Optional string description of the image; eg to use for accessibility."
"additionalProperties":
{
"type" : "string",
"description" : "A key value pair where the key is a language, and the value is the content in that language."
}
}
}
},
Expand Down
9 changes: 9 additions & 0 deletions pyxform/survey.py
Original file line number Diff line number Diff line change
Expand Up @@ -1096,6 +1096,15 @@ def itext(self) -> DetachableElement:
toParseString=output_inserted,
)
)
elif media_type == "image-description":
itext_nodes.append(
node(
"value",
value,
form=media_type,
toParseString=output_inserted,
)
)
elif value != "-":
itext_nodes.append(
node(
Expand Down
10 changes: 10 additions & 0 deletions pyxform/survey_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,16 @@ def xml_label_and_hint(self, survey: "Survey") -> list["DetachableElement"]:
"To use big-image, you must also specify an image for the survey element named {self.name}."
)

# image-description must be associated with an image
if (
self.media is not None
and "image" not in self.media
and "image-description" in self.media
):
raise PyXFormError(
"To use image-description, you must also specify an image for the survey element named {self.name}."
)

return result

def xml_bindings(
Expand Down
13 changes: 13 additions & 0 deletions pyxform/validators/pyxform/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
"If this is intentional, use the setting 'allow_choice_duplicates'. "
"Learn more: https://xlsform.org/#choice-names."
)
MISSING_IMAGE = (
"[row : {row}] On the 'choices' sheet, an 'image' has not been specified. "
"Choices with 'big-image' or 'image-description' require a corresponding image. "
"Learn more: https://xlsform.org/en/#the-choices-worksheet"
)


def validate_headers(
Expand Down Expand Up @@ -55,6 +60,14 @@ def validate_choice_list(
else:
seen_options.add(name)

# Check the option's media, if specified, is mutually consistent
if "media" in option:
media = option["media"]
if "image" not in media and (
"big-image" in media or "image-description" in media
):
duplicate_errors.append(MISSING_IMAGE.format(row=option["__row"]))

if 0 < len(duplicate_errors):
raise PyXFormError("\n".join(duplicate_errors))

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added tests/example_xls/image-description.xlsx
Binary file not shown.
Binary file not shown.
Binary file added tests/example_xls/media-image-description.xlsx
Binary file not shown.
Binary file not shown.
89 changes: 89 additions & 0 deletions tests/test_expected_output/image-description.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?xml version="1.0"?>
<h:html
xmlns="http://www.w3.org/2002/xforms"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jr="http://openrosa.org/javarosa"
xmlns:orx="http://openrosa.org/xforms"
xmlns:odk="http://www.opendatakit.org/xforms">
<h:head>
<h:title>image-description</h:title>
<model odk:xforms-version="1.0.0">
<itext>
<translation lang="default" default="true()">
<text id="animals-0">
<value>whale</value>
<value form="image">jr://images/a.jpg</value>
<value form="image-description">whale silhouette</value>
</text>
<text id="animals-1">
<value>frog</value>
<value form="image">jr://images/b.jpg</value>
<value form="image-description">frog silhouette</value>
</text>
<text id="animals-2">
<value>crocodile</value>
<value form="image">jr://images/c.jpg</value>
<value form="image-description">crocodile silhouette</value>
</text>
<text id="animals-3">
<value>eagle</value>
<value form="image">jr://images/d.jpg</value>
<value form="image-description">eagle silhouette</value>
</text>
<text id="/data/name:label">
<value>What is your name</value>
<value form="image">jr://images/small.jpg</value>
<value form="image-description">small car</value>
</text>
</translation>
</itext>
<instance>
<data id="image-description">
<name/>
<animal/>
<meta>
<instanceID/>
</meta>
</data>
</instance>
<instance id="animals">
<root>
<item>
<itextId>animals-0</itextId>
<name>a</name>
</item>
<item>
<itextId>animals-1</itextId>
<name>b</name>
</item>
<item>
<itextId>animals-2</itextId>
<name>c</name>
</item>
<item>
<itextId>animals-3</itextId>
<name>d</name>
</item>
</root>
</instance>
<bind nodeset="/data/name" type="string"/>
<bind nodeset="/data/animal" type="string"/>
<bind nodeset="/data/meta/instanceID" type="string" readonly="true()" jr:preload="uid"/>
</model>
</h:head>
<h:body>
<input ref="/data/name">
<label ref="jr:itext('/data/name:label')"/>
</input>
<select1 ref="/data/animal">
<label>Pick your favorite animal</label>
<itemset nodeset="instance('animals')/root/item">
<value ref="name"/>
<label ref="jr:itext(itextId)"/>
</itemset>
</select1>
</h:body>
</h:html>

121 changes: 121 additions & 0 deletions tests/test_expected_output/image-description_translated.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?xml version="1.0"?>
<h:html
xmlns="http://www.w3.org/2002/xforms"
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jr="http://openrosa.org/javarosa"
xmlns:orx="http://openrosa.org/xforms"
xmlns:odk="http://www.opendatakit.org/xforms">
<h:head>
<h:title>image-description_translated</h:title>
<model odk:xforms-version="1.0.0">
<itext>
<translation lang="English (en)" default="true()">
<text id="animals-0">
<value>whale</value>
<value form="image">jr://images/a.jpg</value>
<value form="image-description">whale silhouette</value>
</text>
<text id="animals-1">
<value>frog</value>
<value form="image">jr://images/b.jpg</value>
<value form="image-description">frog silhouette</value>
</text>
<text id="animals-2">
<value>crocodile</value>
<value form="image">jr://images/c.jpg</value>
<value form="image-description">crocodile silhouette</value>
</text>
<text id="animals-3">
<value>eagle</value>
<value form="image">jr://images/d.jpg</value>
<value form="image-description">eagle silhouette</value>
</text>
<text id="/data/name:label">
<value>What is your name</value>
<value form="image">jr://images/small.jpg</value>
<value form="image-description">small car</value>
</text>
<text id="/data/animal:label">
<value>Pick your favorite animal</value>
</text>
</translation>
<translation lang="French (fr)">
<text id="animals-0">
<value>baleine</value>
<value form="image">jr://images/a.jpg</value>
<value form="image-description">silhouette de baleine</value>
</text>
<text id="animals-1">
<value>grenouille</value>
<value form="image">jr://images/b.jpg</value>
<value form="image-description">silhouette de grenouille</value>
</text>
<text id="animals-2">
<value>crocodile</value>
<value form="image">jr://images/c.jpg</value>
<value form="image-description">silhouette de crocodile</value>
</text>
<text id="animals-3">
<value>aigle</value>
<value form="image">jr://images/d.jpg</value>
<value form="image-description">silhouette d'aigle</value>
</text>
<text id="/data/name:label">
<value>Quel est ton nom</value>
<value form="image">jr://images/small.jpg</value>
<value form="image-description">petite voiture</value>
</text>
<text id="/data/animal:label">
<value>Choisissez votre animal préféré</value>
</text>
</translation>
</itext>
<instance>
<data id="image-description_translated">
<name/>
<animal/>
<meta>
<instanceID/>
</meta>
</data>
</instance>
<instance id="animals">
<root>
<item>
<itextId>animals-0</itextId>
<name>a</name>
</item>
<item>
<itextId>animals-1</itextId>
<name>b</name>
</item>
<item>
<itextId>animals-2</itextId>
<name>c</name>
</item>
<item>
<itextId>animals-3</itextId>
<name>d</name>
</item>
</root>
</instance>
<bind nodeset="/data/name" type="string"/>
<bind nodeset="/data/animal" type="string"/>
<bind nodeset="/data/meta/instanceID" type="string" readonly="true()" jr:preload="uid"/>
</model>
</h:head>
<h:body>
<input ref="/data/name">
<label ref="jr:itext('/data/name:label')"/>
</input>
<select1 ref="/data/animal">
<label ref="jr:itext('/data/animal:label')"/>
<itemset nodeset="instance('animals')/root/item">
<value ref="name"/>
<label ref="jr:itext(itextId)"/>
</itemset>
</select1>
</h:body>
</h:html>
Loading