From 1ee859a1c25f327058a539b1c3af30b90316f107 Mon Sep 17 00:00:00 2001 From: Will Abbott Date: Mon, 7 Oct 2024 17:58:01 +0100 Subject: [PATCH 1/4] a start --- django_cotton/templatetags/_component.py | 3 +++ django_cotton/tests/test_attributes.py | 32 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/django_cotton/templatetags/_component.py b/django_cotton/templatetags/_component.py index fae33f3..727f9d4 100644 --- a/django_cotton/templatetags/_component.py +++ b/django_cotton/templatetags/_component.py @@ -39,6 +39,9 @@ def render(self, context): value = self._strip_quotes_safely(value) if value is True: # Boolean attribute component_data["attrs"][key] = True + elif key.startswith("::"): # Escaping 1 colon e.g for shorthand alpine + key = key[1:] + component_data["slots"][key] = value elif key.startswith(":"): key = key[1:] try: diff --git a/django_cotton/tests/test_attributes.py b/django_cotton/tests/test_attributes.py index e8a9f75..c7580df 100644 --- a/django_cotton/tests/test_attributes.py +++ b/django_cotton/tests/test_attributes.py @@ -483,3 +483,35 @@ def test_attributes_remain_unordered(self): self.assertTrue( "in default slot: " in compiled ) + + def test_colon_escaping(self): + self.create_template( + "cotton/colon_escaping.html", + """ + attrs: "{{ attrs }}" + + string: "{{ string }}" + dynamic: "{{ dynamic }}" + complex-string: "{{ complex_string }}" + complex-dynamic: "{{ complex_dynamic }}" + """, + ) + + self.create_template( + "colon_escaping_view.html", + """ + + """, + "view/", + context={"variable": "Ive been resolved!"}, + ) + with self.settings(ROOT_URLCONF=self.url_conf()): + response = self.client.get("/view/") + print(response.content.decode()) + self.assertContains(response, 'attrs: ":static="variable" dynamic="Ive been resolved!"') + self.assertContains(response, ':static: "variable"') + self.assertContains(response, 'dynamic: "Ive been resolved!"') From 9935d9143bb502e68c39093eb1b64541e689437e Mon Sep 17 00:00:00 2001 From: Will Abbott Date: Fri, 29 Nov 2024 12:04:25 +0000 Subject: [PATCH 2/4] completed feature, fixed test, added docs --- django_cotton/templatetags/_component.py | 3 ++- django_cotton/tests/test_attributes.py | 16 +++++-------- .../docs_project/templates/alpine_js.html | 24 +++++++++++-------- .../docs_project/templates/components.html | 16 +++++++++++++ 4 files changed, 38 insertions(+), 21 deletions(-) diff --git a/django_cotton/templatetags/_component.py b/django_cotton/templatetags/_component.py index 734f5ee..3dcf130 100644 --- a/django_cotton/templatetags/_component.py +++ b/django_cotton/templatetags/_component.py @@ -42,7 +42,8 @@ def render(self, context): component_data["attrs"][key] = True elif key.startswith("::"): # Escaping 1 colon e.g for shorthand alpine key = key[1:] - component_data["slots"][key] = value + # component_data["slots"][key] = value + component_data["attrs"][key] = value elif key.startswith(":"): key = key[1:] try: diff --git a/django_cotton/tests/test_attributes.py b/django_cotton/tests/test_attributes.py index c7580df..1f7aca3 100644 --- a/django_cotton/tests/test_attributes.py +++ b/django_cotton/tests/test_attributes.py @@ -488,12 +488,7 @@ def test_colon_escaping(self): self.create_template( "cotton/colon_escaping.html", """ - attrs: "{{ attrs }}" - - string: "{{ string }}" - dynamic: "{{ dynamic }}" - complex-string: "{{ complex_string }}" - complex-dynamic: "{{ complex_dynamic }}" + attrs: '{{ attrs }}' """, ) @@ -511,7 +506,8 @@ def test_colon_escaping(self): ) with self.settings(ROOT_URLCONF=self.url_conf()): response = self.client.get("/view/") - print(response.content.decode()) - self.assertContains(response, 'attrs: ":static="variable" dynamic="Ive been resolved!"') - self.assertContains(response, ':static: "variable"') - self.assertContains(response, 'dynamic: "Ive been resolved!"') + + self.assertContains( + response, + """attrs: ':string="variable" dynamic="Ive been resolved!" :complex-string="{'something': 1}" complex-dynamic="{'something': 1}"'""", + ) diff --git a/docs/docs_project/docs_project/templates/alpine_js.html b/docs/docs_project/docs_project/templates/alpine_js.html index 7a5697b..b479d0d 100644 --- a/docs/docs_project/docs_project/templates/alpine_js.html +++ b/docs/docs_project/docs_project/templates/alpine_js.html @@ -14,6 +14,10 @@

Re-usable tabs with alpine.js

+ + Be sure to checkout the notes on alpine.js support here. + +

Let's tackle together a common UI requirement - tabs.

We'll start by defining some goals:

@@ -69,7 +73,7 @@

Preparing cotton components

Now we have the design right, let's chop it up into components.

-

Tabs component

+

{{ ''|force_escape }} component

{% cotton_verbatim %}{% verbatim %}
@@ -85,7 +89,7 @@

Tabs component

{% endcotton_verbatim %}{% endverbatim %} -

Tab component

+

{{ ''|force_escape }} component

{% cotton_verbatim %}{% verbatim %}
@@ -194,13 +198,13 @@

Usage and example

- - - Form Inputs - - - Layouts - - + + + Form Inputs + + + Layouts + + \ No newline at end of file diff --git a/docs/docs_project/docs_project/templates/components.html b/docs/docs_project/docs_project/templates/components.html index 1aa2db1..4eb6b24 100644 --- a/docs/docs_project/docs_project/templates/components.html +++ b/docs/docs_project/docs_project/templates/components.html @@ -11,6 +11,7 @@

Components

Boolean Attributes Dynamic Components Context Isolation + Alpine.js Support Summary of concepts @@ -330,6 +331,21 @@

9. Context Isolation with `only`

+

10. Alpine.js support

+ +

The following key features allow you to build re-usable components with alpine.js:

+ + +
  • + x-data is accessible as {% verbatim %}{{ x_data }}{% endverbatim %} inside the component as cotton makes available snake_case versions of all kebab-cased attributes. (If you use {% verbatim %}{{ attrs }}{% endverbatim %} then the output will already be in the correct case). +
  • +
  • Shorthand x-bind support (:example). As single : attribute prefixing is reserved for cotton's dynamic attributes, + we can escape the first colon using ::. This will ensure the attribute maintains a single : inside {% verbatim %}{{ attrs }}{% endverbatim %} +
  • +
    + + +

    Summary of Concepts

    • {% verbatim %}{{ slot }}{% endverbatim %} - Default content injection.
    • From f147aec7dee95051784dbdf576ea568e06ba3320 Mon Sep 17 00:00:00 2001 From: Will Abbott Date: Fri, 29 Nov 2024 12:05:36 +0000 Subject: [PATCH 3/4] docs fix --- docs/docs_project/docs_project/templates/components.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs_project/docs_project/templates/components.html b/docs/docs_project/docs_project/templates/components.html index 4eb6b24..89fcb0b 100644 --- a/docs/docs_project/docs_project/templates/components.html +++ b/docs/docs_project/docs_project/templates/components.html @@ -339,7 +339,7 @@

      10. Alpine.js support

    • x-data is accessible as {% verbatim %}{{ x_data }}{% endverbatim %} inside the component as cotton makes available snake_case versions of all kebab-cased attributes. (If you use {% verbatim %}{{ attrs }}{% endverbatim %} then the output will already be in the correct case).
    • -
    • Shorthand x-bind support (:example). As single : attribute prefixing is reserved for cotton's dynamic attributes, +
    • Shorthand x-bind support (:example). Because single : attribute prefixing is reserved for cotton's dynamic attributes, we can escape the first colon using ::. This will ensure the attribute maintains a single : inside {% verbatim %}{{ attrs }}{% endverbatim %}
    • From 8d8c2c74fe225288dcdab776ea8f29ad85a556f2 Mon Sep 17 00:00:00 2001 From: Will Abbott Date: Fri, 29 Nov 2024 12:07:38 +0000 Subject: [PATCH 4/4] version bump --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c4334eb..4ab94d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "django-cotton" -version = "1.4.0" +version = "1.5.0" description = "Bringing component based design to Django templates." authors = [ "Will Abbott ",] license = "MIT"