diff --git a/questionpy_sdk/webserver/question_ui/__init__.py b/questionpy_sdk/webserver/question_ui/__init__.py index b311f3b..144ed38 100644 --- a/questionpy_sdk/webserver/question_ui/__init__.py +++ b/questionpy_sdk/webserver/question_ui/__init__.py @@ -76,10 +76,26 @@ def _set_element_value(element: etree._Element, value: str, name: str, xpath: et element.set("value", value) -def _replace_shuffled_indices(element: etree._Element, index: int) -> None: +def _check_shuffled_index_is_in_nested_shuffle_contents( + container: etree._Element, index_element: etree._Element +) -> bool: + ancestor = index_element.getparent() + while ancestor is not None and ancestor != container: + if f"{{{_QPY_NAMESPACE}}}shuffle-contents" in ancestor.attrib: + return True + ancestor = ancestor.getparent() + return False + + +def _replace_shuffled_indices(container: etree._Element, element: etree._Element, index: int) -> None: for index_element in _assert_element_list( element.xpath(".//qpy:shuffled-index", namespaces={"qpy": _QPY_NAMESPACE}) ): + if _check_shuffled_index_is_in_nested_shuffle_contents(container, index_element): + # The index element is in a nested shuffle-contents. + # We want it to be replaced with the index of the inner shuffle, so we ignore it for now. + continue + format_style = index_element.get("format", "123") if format_style == "123": @@ -394,14 +410,14 @@ def _shuffle_contents(self) -> None: child_elements = [child for child in element if isinstance(child, etree._Element)] self._random.shuffle(child_elements) - element.attrib.pop(f"{{{_QPY_NAMESPACE}}}shuffle-contents") - # Reinsert shuffled elements, preserving non-element nodes - for i, child in enumerate(child_elements): - _replace_shuffled_indices(child, i + 1) + for i, child in enumerate(child_elements, 1): + _replace_shuffled_indices(element, child, i) # Move each child element back to its parent at the correct position element.append(child) + element.attrib.pop(f"{{{_QPY_NAMESPACE}}}shuffle-contents") + def _clean_up(self) -> None: """Removes remaining QuestionPy elements and attributes as well as comments and xmlns declarations.""" for element in _assert_element_list(self._xpath("//qpy:*")): diff --git a/tests/questionpy_sdk/webserver/test_data/shuffled-index-nested.xhtml b/tests/questionpy_sdk/webserver/test_data/shuffled-index-nested.xhtml new file mode 100644 index 0000000..374a464 --- /dev/null +++ b/tests/questionpy_sdk/webserver/test_data/shuffled-index-nested.xhtml @@ -0,0 +1,8 @@ +
i. B
+ii. A
+i. D
+ii. C
+