Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add turbo stream morph actions to broadcasts #583

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/channels/turbo/streams/broadcasts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ def refresh_debouncer_for(*streamables, request_id: nil) # :nodoc:
Turbo::ThreadDebouncer.for("turbo-refresh-debouncer-#{stream_name_from(streamables.including(request_id))}")
end

def broadcast_morph_to(*streamables, **opts)
broadcast_action_to(*streamables, action: :morph, **opts)
end

def broadcast_morph_later_to(*streamables, **opts)
broadcast_action_later_to(*streamables, action: :morph, **opts)
end

private
def render_format(format, **rendering)
ApplicationController.render(formats: [ format ], **rendering)
Expand Down
23 changes: 23 additions & 0 deletions app/models/concerns/turbo/broadcastable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,29 @@ def broadcast_render_later_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_render_later_to(*streamables, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
end

# Broadcast a morph action to the stream name identified by the passed <tt>streamables</tt>. Example:
# sends <turbo-stream action="morph" target="clearance_5"><template><div id="clearance_5">My Clearance</div></template></turbo-stream>
# to the stream named "identity:2:clearances"
# clearance.broadcast_morph_to examiner.identity, :clearances
def broadcast_morph_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_morph_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
end

# Same as <tt>broadcast_morph_to</tt> but the designated stream is automatically set to the current model.
def broadcast_morph(**rendering)
broadcast_morph_to(self, target: self, **rendering)
end

# Same as <tt>broadcast_morph_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
def broadcast_morph_later_to(*streamables, **rendering)
Turbo::StreamsChannel.broadcast_morph_later_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
end

# Same as <tt>broadcast_morph_later_to</tt> but the designated stream is automatically set to the current model.
def broadcast_morph_later(target: broadcast_target_default, **rendering)
broadcast_morph_later_to self, **rendering
end

private
def broadcast_target_default
self.class.broadcast_target_default
Expand Down
26 changes: 26 additions & 0 deletions app/models/turbo/streams/tag_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,32 @@ def prepend_all(targets, content = nil, **rendering, &block)
action_all :prepend, targets, content, **rendering, &block
end

# Morph the <tt>target</tt> in the dom with either the <tt>content</tt> passed in or a rendering result determined
# by the <tt>rendering</tt> keyword arguments, the content in the block, or the rendering of the target as a record. Examples:
#
# <%= turbo_stream.morph "clearance_5", "<div id='clearance_5'>Morph the dom target identified by clearance_5</div>" %>
# <%= turbo_stream.morph clearance %>
# <%= turbo_stream.morph clearance, partial: "clearances/clearance", locals: { title: "Hello" } %>
# <%= turbo_stream.morph "clearance_5" do %>
# <div id='clearance_5'>Morph the dom target identified by clearance_5</div>
# <% end %>
def morph(target, content = nil, **rendering, &block)
action :morph, target, content, **rendering, &block
end

# Morph the <tt>targets</tt> in the dom with either the <tt>content</tt> passed in or a rendering result determined
# by the <tt>rendering</tt> keyword arguments, the content in the block, or the rendering of the targets as a record. Examples:
#
# <%= turbo_stream.morph_all ".clearance_item", "<div class='clearance_item'>Morph the dom target identified by the class clearance_item</div>" %>
# <%= turbo_stream.morph_all clearance %>
# <%= turbo_stream.morph_all clearance, partial: "clearances/clearance", locals: { title: "Hello" } %>
# <%= turbo_stream.morph_all ".clearance_item" do %>
# <div class='clearance_item'>Morph the dom target identified by the class clearance_item</div>
# <% end %>
def morph_all(targets, content = nil, **rendering, &block)
action_all :morph, targets, content, **rendering, &block
end

# Send an action of the type <tt>name</tt> to <tt>target</tt>. Options described in the concrete methods.
def action(name, target, content = nil, allow_inferred_rendering: true, **rendering, &block)
template = render_template(target, content, allow_inferred_rendering: allow_inferred_rendering, **rendering, &block)
Expand Down
50 changes: 48 additions & 2 deletions test/streams/broadcastable_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,30 @@ class Turbo::BroadcastableTest < ActionCable::Channel::TestCase
@message.broadcast_render_to @profile
end
end

test "broadcasting morph to stream now" do
assert_broadcast_on "stream", turbo_stream_action_tag("morph", target: "message_1", template: render(@message)) do
@message.broadcast_morph_to "stream", target: "message_1"
end
end

test "broadcasting morph to stream now targeting children-only children-only" do
assert_broadcast_on "stream", turbo_stream_action_tag("morph", target: "message_1", 'children-only': true, template: render(@message)) do
@message.broadcast_morph_to "stream", target: "message_1", attributes: { 'children-only': true }
end
end

test "broadcasting morph now" do
omarluq marked this conversation as resolved.
Show resolved Hide resolved
assert_broadcast_on @message.to_gid_param, turbo_stream_action_tag("morph", target: "message_1", template: render(@message)) do
@message.broadcast_morph target: "message_1"
end
end

test "broadcasting morph now targeting children-only" do
assert_broadcast_on @message.to_gid_param, turbo_stream_action_tag("morph", target: "message_1", 'children-only': true, template: render(@message)) do
@message.broadcast_morph target: "message_1", attributes: { 'children-only': true }
end
end
end

class Turbo::BroadcastableArticleTest < ActionCable::Channel::TestCase
Expand Down Expand Up @@ -518,6 +542,30 @@ class Turbo::SuppressingBroadcastsTest < ActionCable::Channel::TestCase
end
end

test "suppressing broadcasting morph to stream now" do
assert_no_broadcasts_when_suppressing do
@message.broadcast_morph_to "stream"
end
end

test "suppressing broadcasting morph to stream later" do
assert_no_broadcasts_later_when_supressing do
@message.broadcast_morph_later_to "stream"
end
end

test "suppressing broadcasting morph now" do
assert_no_broadcasts_when_suppressing do
@message.broadcast_morph
end
end

test "suppressing broadcasting morph later" do
assert_no_broadcasts_later_when_supressing do
@message.broadcast_morph_later
end
end

private
def assert_no_broadcasts_when_suppressing
assert_no_broadcasts @message.to_gid_param do
Expand All @@ -535,5 +583,3 @@ def assert_no_broadcasts_later_when_supressing
end
end
end


30 changes: 30 additions & 0 deletions test/streams/streams_channel_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -255,4 +255,34 @@ class Turbo::StreamsChannelTest < ActionCable::Channel::TestCase
Turbo::StreamsChannel.broadcast_stream_to "stream", content: "direct"
end
end

test "broadcasting morph now" do
options = { partial: "messages/message", locals: { message: "hello!" } }

assert_broadcast_on "stream", turbo_stream_action_tag("morph", target: "message_1", template: render(options)) do
Turbo::StreamsChannel.broadcast_morph_to "stream", target: "message_1", **options
end

assert_broadcast_on "stream", turbo_stream_action_tag("morph", targets: ".message", template: render(options)) do
Turbo::StreamsChannel.broadcast_morph_to "stream", targets: ".message", **options
end
end

test "broadcasting morph later" do
options = { partial: "messages/message", locals: { message: "hello!" } }

assert_broadcast_on "stream", turbo_stream_action_tag("morph", target: "message_1", template: render(options)) do
perform_enqueued_jobs do
Turbo::StreamsChannel.broadcast_morph_later_to \
"stream", target: "message_1", **options
end
end

assert_broadcast_on "stream", turbo_stream_action_tag("morph", targets: ".message", template: render(options)) do
perform_enqueued_jobs do
Turbo::StreamsChannel.broadcast_morph_later_to \
"stream", targets: ".message", **options
end
end
end
end
Loading