From fd0f179425619ce614b40f61cd3254681b3b3c66 Mon Sep 17 00:00:00 2001 From: Christopher Grande Date: Mon, 27 Nov 2023 17:46:43 -0500 Subject: [PATCH] Adds turbo_refreshes_with template tag For support for morphing coming in Turbo 8, https://github.com/hotwired/turbo/pull/1019 Duplicates the Rails turbo_refreshes_with template helper. Updated docs and helper --- docs/source/morphing.md | 21 +++++++++++ src/turbo_helper/templatetags/turbo_helper.py | 18 ++++++++++ tests/test_tags.py | 35 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 docs/source/morphing.md diff --git a/docs/source/morphing.md b/docs/source/morphing.md new file mode 100644 index 0000000..762b5f6 --- /dev/null +++ b/docs/source/morphing.md @@ -0,0 +1,21 @@ +## turbo_refreshes_with + +This template tag generates HTML meta tags for Turbo Drive to control the refresh method and scroll behavior in Turbo 8.0+ ([currently in beta](https://github.com/hotwired/turbo/releases/tag/v8.0.0-beta.4)). + +### Parameters + +- `method` (optional, default: `'replace'`): Specifies the refresh method. Must be one of `'replace'` or `'morph'`. +- `scroll` (optional, default: `'reset'`): Specifies the scroll behavior. Must be one of `'reset'` or `'preserve'`. + +### Behavior + +This tag creates HTML meta tags defining the Turbo Frames' refresh method and scroll behavior based on the provided parameters. If the provided parameters are not within the valid options, a `ValidationError` is raised. + +### Example Usage + +```django +{% load turbo_helper %} + + +{% turbo_refreshes_with method='replace' scroll='reset' %} +``` diff --git a/src/turbo_helper/templatetags/turbo_helper.py b/src/turbo_helper/templatetags/turbo_helper.py index be239c8..1ef413b 100644 --- a/src/turbo_helper/templatetags/turbo_helper.py +++ b/src/turbo_helper/templatetags/turbo_helper.py @@ -3,7 +3,9 @@ from django import template from django.db.models.base import Model from django.template import Node, TemplateSyntaxError +from django.core.exceptions import ValidationError from django.template.base import token_kwargs +from django.utils.html import format_html from turbo_helper.renderers import render_turbo_frame, render_turbo_stream_from from turbo_helper.stream import action_proxy @@ -260,3 +262,19 @@ def turbo_stream_from_tag(parser, token): stream_name_array = [parser.compile_filter(bit) for bit in remaining_bits] return TurboStreamFromTagNode(stream_name_array) + + +@register.simple_tag +def turbo_refreshes_with(method='replace', scroll='reset') -> str: + valid_methods = ['replace', 'morph'] + valid_scrolls = ['reset', 'preserve'] + + if method not in valid_methods: + raise ValidationError(f"Invalid refresh option '{method}'") + if scroll not in valid_scrolls: + raise ValidationError(f"Invalid scroll option '{scroll}'") + + meta_tags = f'' + meta_tags += f'' + + return format_html(meta_tags) diff --git a/tests/test_tags.py b/tests/test_tags.py index 447912c..f4041c3 100644 --- a/tests/test_tags.py +++ b/tests/test_tags.py @@ -1,4 +1,5 @@ import pytest +from django.core.exceptions import ValidationError from django.template import Context, Template from tests.testapp.models import TodoItem @@ -169,3 +170,37 @@ def test_dom_id_variable(self): output == '' ) + + +class TestRefreshesWith: + def test_turbo_refreshes_with_tag(self): + template = """ + {% load turbo_helper %} + + {% turbo_refreshes_with method='replace' scroll='reset' %} + """ + + output = render(template, {}).strip() + + expected_method_tag = '' + expected_scroll_tag = '' + + assert expected_method_tag in output + assert expected_scroll_tag in output + + def test_invalid_options(self): + with pytest.raises(ValidationError): + template = """ + {% load turbo_helper %} + + {% turbo_refreshes_with method='invalid' scroll='reset' %} + """ + output = render(template, {}).strip() + + with pytest.raises(ValidationError): + template = """ + {% load turbo_helper %} + + {% turbo_refreshes_with method='replace' scroll='invalid' %} + """ + output = render(template, {}).strip()