Skip to content

Commit

Permalink
Add turbo_power support (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-yin authored Jan 17, 2024
1 parent 6d9c2bd commit b93d262
Show file tree
Hide file tree
Showing 6 changed files with 552 additions and 9 deletions.
5 changes: 3 additions & 2 deletions src/turbo_helper/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from .constants import TURBO_STREAM_MIME_TYPE as TURBO_STREAM_CONTENT_TYPE
from .constants import ResponseFormat
from .response import HttpResponseSeeOther, TurboStreamResponse
from .shortcuts import redirect_303, response_format
from .stream import register_turbo_stream_action, turbo_stream
from .templatetags.turbo_helper import dom_id

# extend turbo_stream actions, inspired by https://github.com/marcoroth/turbo_power
from .turbo_power import * # noqa

__all__ = [
"turbo_stream",
"register_turbo_stream_action",
Expand All @@ -14,5 +16,4 @@
"dom_id",
"response_format",
"ResponseFormat",
"TURBO_STREAM_CONTENT_TYPE",
]
7 changes: 6 additions & 1 deletion src/turbo_helper/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ def render_turbo_stream(

element_attributes_array = []
for key, value in element_attributes.items():
if value is None:
continue
# TODO: bool type django/forms/widgets/attrs.html
element_attributes_array.append(f'{key}="{escape(value)}"')

attribute_string = mark_safe(" ".join(element_attributes_array))

django_engine = engines["django"]
template_string = """<turbo-stream action="{{ action }}"{% if target %} target="{{ target }}"{% else %} targets="{{ targets }}"{% endif %}{% if attribute_string %} {{ attribute_string }}{% endif %}><template>{{ content|default:'' }}</template></turbo-stream>"""
template_string = """<turbo-stream action="{{ action }}"{% if target %} target="{{ target }}"{% elif targets %} targets="{{ targets }}"{% endif %}{% if attribute_string %} {{ attribute_string }}{% endif %}><template>{{ content|default:'' }}</template></turbo-stream>"""
context = {
"content": content,
"action": action,
Expand All @@ -43,13 +45,16 @@ def render_turbo_frame(frame_id: str, content: str, attributes: Dict[str, Any])
# convert data_xxx to data-xxx
element_attributes = {}
for key, value in attributes.items():
# convert data_xxx to data-xxx
if key.startswith("data"):
element_attributes[key.replace("_", "-")] = value
else:
element_attributes[key] = value

element_attributes_array = []
for key, value in element_attributes.items():
if value is None:
continue
# TODO: bool type django/forms/widgets/attrs.html
element_attributes_array.append(f'{key}="{escape(value)}"')

Expand Down
24 changes: 18 additions & 6 deletions src/turbo_helper/templatetags/turbo_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,24 @@ def render(self, context):
)
elif targets:
action = self.action.resolve(context)
func = getattr(turbo_stream, f"{action}_all")
return func(
targets=targets,
content=children,
**attributes,
)
func = getattr(turbo_stream, f"{action}_all", None)

if func:
return func(
targets=targets,
content=children,
**attributes,
)
else:
# fallback to pass targets to the single target handler
# we do this because of turbo_power
action = self.action.resolve(context)
func = getattr(turbo_stream, f"{action}")
return func(
targets=targets,
content=children,
**attributes,
)


class TurboStreamFromTagNode(Node):
Expand Down
153 changes: 153 additions & 0 deletions src/turbo_helper/turbo_power.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
"""
https://github.com/marcoroth/turbo_power-rails
Bring turbo_power to Django
"""
import json

from django.utils.safestring import mark_safe

from turbo_helper import register_turbo_stream_action, turbo_stream


def transform_attributes(attributes):
transformed_attributes = {}
for key, value in attributes.items():
transformed_key = transform_key(key)
transformed_value = transform_value(value)
transformed_attributes[transformed_key] = transformed_value
return transformed_attributes


def transform_key(key):
return str(key).replace("_", "-")


def transform_value(value):
if isinstance(value, str):
return value
elif isinstance(value, (int, float, bool)):
return str(value).lower()
elif value is None:
return None
else:
return json.dumps(value)


################################################################################


def custom_action(action, target=None, content=None, **kwargs):
return turbo_stream.action(
action, target=target, content=content, **transform_attributes(kwargs)
)


def custom_action_all(action, targets=None, content=None, **kwargs):
return turbo_stream.action_all(
action, targets=targets, content=content, **transform_attributes(kwargs)
)


# DOM Actions


@register_turbo_stream_action("graft")
def graft(targets=None, parent=None, **attributes):
return custom_action_all(
"graft",
targets=targets,
parent=parent,
**attributes,
)


@register_turbo_stream_action("morph")
def morph(targets=None, html=None, **attributes):
html = html or attributes.pop("content", None)
return custom_action_all(
"morph",
targets=targets,
content=mark_safe(html) if html else None,
**attributes,
)


# Attribute Actions


@register_turbo_stream_action("add_css_class")
def add_css_class(targets=None, classes="", **attributes):
classes = attributes.get("classes", classes)
if isinstance(classes, list):
classes = " ".join(classes)

return custom_action_all(
"add_css_class",
targets=targets,
classes=classes,
**attributes,
)


# Event Actions


@register_turbo_stream_action("dispatch_event")
def dispatch_event(targets=None, name=None, detail=None, **attributes):
detail = detail or {}
return custom_action_all(
"dispatch_event",
targets=targets,
name=name,
content=mark_safe(json.dumps(detail, separators=(",", ":"))),
**attributes,
)


# Notification Actions


@register_turbo_stream_action("notification")
def notification(title=None, **attributes):
return custom_action(
"notification",
title=title,
**attributes,
)


# Turbo Actions


@register_turbo_stream_action("redirect_to")
def redirect_to(url=None, turbo_action="advance", turbo_frame=None, **attributes):
return custom_action(
"redirect_to",
url=url,
turbo_action=turbo_action,
turbo_frame=turbo_frame,
**attributes,
)


# Turbo Frame Actions


@register_turbo_stream_action("turbo_frame_reload")
def turbo_frame_reload(target=None, **attributes):
return custom_action(
"turbo_frame_reload",
target=target,
**attributes,
)


@register_turbo_stream_action("turbo_frame_set_src")
def turbo_frame_set_src(target=None, src=None, **attributes):
return custom_action(
"turbo_frame_set_src",
target=target,
src=src,
**attributes,
)
Loading

0 comments on commit b93d262

Please sign in to comment.