diff --git a/README.md b/README.md index d35c747..fd67716 100644 --- a/README.md +++ b/README.md @@ -479,21 +479,20 @@ For full docs and demos, checkout " should be accompanied by an "is" attribute.' ) component_name = is_ @@ -148,13 +115,6 @@ class CottonComponentNode(Node): return value[1:-1] return value - -def get_cotton_data(context): - if "cotton_data" not in context: - context["cotton_data"] = {"stack": [], "vars": {}} - return context["cotton_data"] - - @register.tag("comp") def cotton_component(parser, token): bits = token.split_contents()[1:] @@ -291,3 +251,21 @@ def cotton_vars(parser, token): parser.delete_first_token() return CottonVarsNode(var_dict, empty_vars, nodelist) + + +@register.filter +def merge(attrs, args): + # attrs is expected to be a dictionary of existing attributes + # args is a string of additional attributes to merge, e.g., "class:extra-class" + for arg in args.split(","): + key, value = arg.split(":", 1) + if key in attrs: + attrs[key] = value + " " + attrs[key] + else: + attrs[key] = value + return format_html_join(" ", '{0}="{1}"', attrs.items()) + + +@register.filter +def get_item(dictionary, key): + return dictionary.get(key) diff --git a/django_cotton/tests/test_attributes.py b/django_cotton/tests/test_attributes.py index a3a1049..4e7d6de 100644 --- a/django_cotton/tests/test_attributes.py +++ b/django_cotton/tests/test_attributes.py @@ -521,3 +521,51 @@ class AttributeHandlingTests(CottonTestCase): with self.settings(ROOT_URLCONF=self.url_conf()): response = self.client.get("/view/") self.assertTrue(response.status_code == 200) + + def test_htmx_attribute_values_single_quote(self): + # tests for json-like values + self.create_template( + "cotton/htmx.html", + """ +
+ """, + ) + + self.create_template( + "htmx_view.html", + """ + + """, + "view/", + ) + + # Override URLconf + with self.settings(ROOT_URLCONF=self.url_conf()): + response = self.client.get("/view/") + self.assertContains(response, """'{"id": "1"}'""") + + def test_htmx_attribute_values_double_quote(self): + # tests for json-like values + self.create_template( + "cotton/htmx2.html", + """ +
+ """, + ) + + self.create_template( + "htmx_view2.html", + """ + + """, + "view/", + ) + + # Override URLconf + with self.settings(ROOT_URLCONF=self.url_conf()): + response = self.client.get("/view/") + self.assertContains(response, "\"{'id': '1'}\"") diff --git a/django_cotton/utils.py b/django_cotton/utils.py index 5e7a98d..4dcc4bc 100644 --- a/django_cotton/utils.py +++ b/django_cotton/utils.py @@ -12,7 +12,15 @@ def eval_string(value): def ensure_quoted(value): - if isinstance(value, str) and value.startswith('"') and value.endswith('"'): - return value - else: - return f'"{value}"' + if isinstance(value, str): + if value.startswith('{"') and value.endswith("}"): + return f"'{value}'" # use single quotes for json-like strings + elif value.startswith('"') and value.endswith('"'): + return value # already quoted + return f'"{value}"' # default to double quotes + + +def get_cotton_data(context): + if "cotton_data" not in context: + context["cotton_data"] = {"stack": [], "vars": {}} + return context["cotton_data"]