diff --git a/plone/app/querystring/registryreader.py b/plone/app/querystring/registryreader.py
index ad6e23f..52401de 100644
--- a/plone/app/querystring/registryreader.py
+++ b/plone/app/querystring/registryreader.py
@@ -94,6 +94,11 @@ def getVocabularyValues(self, values):
else:
title = item.title
translated.append((title, item.value))
+ # We don't need a values_order key if there aren't any values
+ if translated:
+ field["values_order"] = []
+ for title, value in translated:
+ field["values_order"].append(value)
translated = sorted(translated, key=lambda x: id_normalize(safe_text(x[0])))
for title, value in translated:
field["values"][value] = {"title": title}
diff --git a/plone/app/querystring/tests/registry_test_vocabulary.xml b/plone/app/querystring/tests/registry_test_vocabulary.xml
index 529d420..7879581 100644
--- a/plone/app/querystring/tests/registry_test_vocabulary.xml
+++ b/plone/app/querystring/tests/registry_test_vocabulary.xml
@@ -22,4 +22,18 @@
plone.app.querystring.tests.testvocabulary
Metadata
+
+
+ Manually ordered test field
+ True
+ True
+
+ plone.app.querystring.operation.string.is
+
+ plone.app.querystring.tests.testvocabulary_manually_ordered_field
+ Metadata
+
+
diff --git a/plone/app/querystring/tests/testRegistryReader.py b/plone/app/querystring/tests/testRegistryReader.py
index 962ad68..3c1b841 100644
--- a/plone/app/querystring/tests/testRegistryReader.py
+++ b/plone/app/querystring/tests/testRegistryReader.py
@@ -1,3 +1,4 @@
+from collections import OrderedDict
from plone.app.querystring.interfaces import IQuerystringRegistryReader
from plone.app.querystring.registryreader import DottedDict
from plone.app.querystring.testing import PLONEAPPQUERYSTRING_INTEGRATION_TESTING
@@ -19,6 +20,20 @@ def __call__(self, context):
return SimpleVocabulary([SimpleVocabulary.createTerm(term, term, term)])
+@implementer(IVocabularyFactory)
+class TestVocabularyManuallyOrdered:
+ def __call__(self, context):
+ return SimpleVocabulary.fromItems(
+ (
+ ("A", "id_a", "A"),
+ ("E", "id_e", "E"),
+ ("B", "id_b", "B"),
+ ("D", "id_d", "D"),
+ ("C", "id_c", "C"),
+ )
+ )
+
+
class TestRegistryReader(unittest.TestCase):
layer = PLONEAPPQUERYSTRING_INTEGRATION_TESTING
@@ -29,6 +44,11 @@ def setUp(self):
IVocabularyFactory,
"plone.app.querystring.tests.testvocabulary",
)
+ gsm.registerUtility(
+ TestVocabularyManuallyOrdered(),
+ IVocabularyFactory,
+ "plone.app.querystring.tests.testvocabulary_manually_ordered_field",
+ )
def getLogger(self, value):
return "plone.app.querystring"
@@ -85,6 +105,60 @@ def test_get_vocabularies(self):
vocabulary_result = result.get("plone.app.querystring.field.reviewState.values")
self.assertEqual(vocabulary_result, {"term": {"title": "term"}})
+ def test_vocabulary_order_retained(self):
+ """tests if getVocabularyValues is returning the correct vocabulary
+ values in the correct format
+ """
+ registry = self.createRegistry(td.test_vocabulary_xml)
+ reader = IQuerystringRegistryReader(registry)
+ result = reader.parseRegistry()
+ result = reader.getVocabularyValues(result)
+ vocabulary_values = result.get(
+ "plone.app.querystring.field.testvocabulary_manually_ordered.values"
+ )
+
+ # This is here to prove that we are getting sorted titles. We'll check for the manual order shortly
+ self.assertEqual(
+ vocabulary_values,
+ OrderedDict(
+ {
+ "id_a": {"title": "A"},
+ "id_b": {"title": "B"},
+ "id_c": {"title": "C"},
+ "id_d": {"title": "D"},
+ "id_e": {"title": "E"},
+ }
+ ),
+ )
+ vocabulary_values_order = result.get(
+ "plone.app.querystring.field.testvocabulary_manually_ordered.values_order"
+ )
+ self.assertEqual(
+ vocabulary_values_order,
+ [
+ "id_a",
+ "id_e",
+ "id_b",
+ "id_d",
+ "id_c",
+ ],
+ )
+ self.assertEqual(
+ # Re-sort the sorted dictionary based on the correct order
+ OrderedDict(
+ {token: vocabulary_values[token] for token in vocabulary_values_order}
+ ),
+ OrderedDict(
+ {
+ "id_a": {"title": "A"},
+ "id_e": {"title": "E"},
+ "id_b": {"title": "B"},
+ "id_d": {"title": "D"},
+ "id_c": {"title": "C"},
+ }
+ ),
+ )
+
def test_get_vocabularies_in_context(self):
portal = self.layer["portal"]
subsite = portal[portal.invokeFactory("Document", "subsite", title="Subsite")]