turbo-rails 0.5.9 → 0.7.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +19 -14
- data/Rakefile +4 -0
- data/app/assets/javascripts/turbo.js +1230 -807
- data/app/channels/turbo/streams/broadcasts.rb +43 -21
- data/app/helpers/turbo/frames_helper.rb +4 -0
- data/app/helpers/turbo/streams/action_helper.rb +17 -5
- data/app/helpers/turbo/streams_helper.rb +5 -3
- data/app/javascript/turbo/cable.js +6 -3
- data/app/jobs/turbo/streams/action_broadcast_job.rb +2 -0
- data/app/jobs/turbo/streams/broadcast_job.rb +2 -0
- data/app/models/concerns/turbo/broadcastable.rb +79 -16
- data/app/models/turbo/streams/tag_builder.rb +136 -17
- data/lib/install/turbo_needs_redis.rb +9 -0
- data/lib/install/turbo_with_importmap.rb +5 -0
- data/lib/install/turbo_with_node.rb +9 -0
- data/lib/tasks/turbo_tasks.rake +31 -8
- data/lib/turbo/engine.rb +6 -2
- data/lib/turbo/test_assertions.rb +2 -3
- data/lib/turbo/version.rb +1 -1
- metadata +6 -5
- data/lib/install/turbo_with_asset_pipeline.rb +0 -36
- data/lib/install/turbo_with_webpacker.rb +0 -23
@@ -5,49 +5,71 @@
|
|
5
5
|
module Turbo::Streams::Broadcasts
|
6
6
|
include Turbo::Streams::ActionHelper
|
7
7
|
|
8
|
-
def broadcast_remove_to(*streamables,
|
9
|
-
broadcast_action_to
|
8
|
+
def broadcast_remove_to(*streamables, **opts)
|
9
|
+
broadcast_action_to(*streamables, action: :remove, **opts)
|
10
10
|
end
|
11
11
|
|
12
|
-
def broadcast_replace_to(*streamables,
|
13
|
-
broadcast_action_to
|
12
|
+
def broadcast_replace_to(*streamables, **opts)
|
13
|
+
broadcast_action_to(*streamables, action: :replace, **opts)
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
broadcast_action_to
|
16
|
+
def broadcast_update_to(*streamables, **opts)
|
17
|
+
broadcast_action_to(*streamables, action: :update, **opts)
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
21
|
-
broadcast_action_to
|
20
|
+
def broadcast_before_to(*streamables, **opts)
|
21
|
+
broadcast_action_to(*streamables, action: :before, **opts)
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
25
|
-
|
24
|
+
def broadcast_after_to(*streamables, **opts)
|
25
|
+
broadcast_action_to(*streamables, action: :after, **opts)
|
26
|
+
end
|
27
|
+
|
28
|
+
def broadcast_append_to(*streamables, **opts)
|
29
|
+
broadcast_action_to(*streamables, action: :append, **opts)
|
30
|
+
end
|
31
|
+
|
32
|
+
def broadcast_prepend_to(*streamables, **opts)
|
33
|
+
broadcast_action_to(*streamables, action: :prepend, **opts)
|
34
|
+
end
|
35
|
+
|
36
|
+
def broadcast_action_to(*streamables, action:, target: nil, targets: nil, **rendering)
|
37
|
+
broadcast_stream_to(*streamables, content: turbo_stream_action_tag(action, target: target, targets: targets, template:
|
26
38
|
rendering.delete(:content) || (rendering.any? ? render_format(:html, **rendering) : nil)
|
27
|
-
)
|
39
|
+
))
|
28
40
|
end
|
29
41
|
|
42
|
+
def broadcast_replace_later_to(*streamables, **opts)
|
43
|
+
broadcast_action_later_to(*streamables, action: :replace, **opts)
|
44
|
+
end
|
30
45
|
|
31
|
-
def
|
32
|
-
broadcast_action_later_to
|
46
|
+
def broadcast_update_later_to(*streamables, **opts)
|
47
|
+
broadcast_action_later_to(*streamables, action: :update, **opts)
|
33
48
|
end
|
34
49
|
|
35
|
-
def
|
36
|
-
broadcast_action_later_to
|
50
|
+
def broadcast_before_later_to(*streamables, **opts)
|
51
|
+
broadcast_action_later_to(*streamables, action: :before, **opts)
|
37
52
|
end
|
38
53
|
|
39
|
-
def
|
40
|
-
broadcast_action_later_to
|
54
|
+
def broadcast_after_later_to(*streamables, **opts)
|
55
|
+
broadcast_action_later_to(*streamables, action: :after, **opts)
|
41
56
|
end
|
42
57
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
58
|
+
def broadcast_append_later_to(*streamables, **opts)
|
59
|
+
broadcast_action_later_to(*streamables, action: :append, **opts)
|
60
|
+
end
|
61
|
+
|
62
|
+
def broadcast_prepend_later_to(*streamables, **opts)
|
63
|
+
broadcast_action_later_to(*streamables, action: :prepend, **opts)
|
46
64
|
end
|
47
65
|
|
66
|
+
def broadcast_action_later_to(*streamables, action:, target: nil, targets: nil, **rendering)
|
67
|
+
Turbo::Streams::ActionBroadcastJob.perform_later \
|
68
|
+
stream_name_from(streamables), action: action, target: target, targets: targets, **rendering
|
69
|
+
end
|
48
70
|
|
49
71
|
def broadcast_render_to(*streamables, **rendering)
|
50
|
-
broadcast_stream_to
|
72
|
+
broadcast_stream_to(*streamables, content: render_format(:turbo_stream, **rendering))
|
51
73
|
end
|
52
74
|
|
53
75
|
def broadcast_render_later_to(*streamables, **rendering)
|
@@ -16,12 +16,16 @@ module Turbo::FramesHelper
|
|
16
16
|
# <%= turbo_frame_tag "tray", target: "other_tray" %>
|
17
17
|
# # => <turbo-frame id="tray" target="other_tray"></turbo-frame>
|
18
18
|
#
|
19
|
+
# <%= turbo_frame_tag "tray", src: tray_path(tray), loading: "lazy" %>
|
20
|
+
# # => <turbo-frame id="tray" src="http://example.com/trays/1" loading="lazy"></turbo-frame>
|
21
|
+
#
|
19
22
|
# <%= turbo_frame_tag "tray" do %>
|
20
23
|
# <div>My tray frame!</div>
|
21
24
|
# <% end %>
|
22
25
|
# # => <turbo-frame id="tray"><div>My tray frame!</div></turbo-frame>
|
23
26
|
def turbo_frame_tag(id, src: nil, target: nil, **attributes, &block)
|
24
27
|
id = id.respond_to?(:to_key) ? dom_id(id) : id
|
28
|
+
src = url_for(src) if src.present?
|
25
29
|
|
26
30
|
tag.turbo_frame(**attributes.merge(id: id, src: src, target: target).compact, &block)
|
27
31
|
end
|
@@ -6,15 +6,27 @@ module Turbo::Streams::ActionHelper
|
|
6
6
|
#
|
7
7
|
# turbo_stream_action_tag "replace", target: "message_1", template: %(<div id="message_1">Hello!</div>)
|
8
8
|
# # => <turbo-stream action="replace" target="message_1"><template><div id="message_1">Hello!</div></template></turbo-stream>
|
9
|
-
|
10
|
-
|
9
|
+
#
|
10
|
+
# turbo_stream_action_tag "replace", targets: "message_1", template: %(<div id="message_1">Hello!</div>)
|
11
|
+
# # => <turbo-stream action="replace" targets="message_1"><template><div id="message_1">Hello!</div></template></turbo-stream>
|
12
|
+
def turbo_stream_action_tag(action, target: nil, targets: nil, template: nil)
|
11
13
|
template = action.to_sym == :remove ? "" : "<template>#{template}</template>"
|
12
14
|
|
13
|
-
|
15
|
+
if target = convert_to_turbo_stream_dom_id(target)
|
16
|
+
%(<turbo-stream action="#{action}" target="#{target}">#{template}</turbo-stream>).html_safe
|
17
|
+
elsif targets = convert_to_turbo_stream_dom_id(targets, include_selector: true)
|
18
|
+
%(<turbo-stream action="#{action}" targets="#{targets}">#{template}</turbo-stream>).html_safe
|
19
|
+
else
|
20
|
+
raise ArgumentError, "target or targets must be supplied"
|
21
|
+
end
|
14
22
|
end
|
15
23
|
|
16
24
|
private
|
17
|
-
def convert_to_turbo_stream_dom_id(target)
|
18
|
-
target.respond_to?(:to_key)
|
25
|
+
def convert_to_turbo_stream_dom_id(target, include_selector: false)
|
26
|
+
if target.respond_to?(:to_key)
|
27
|
+
[ ("#" if include_selector), ActionView::RecordIdentifier.dom_id(target) ].compact.join
|
28
|
+
else
|
29
|
+
target
|
30
|
+
end
|
19
31
|
end
|
20
32
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Turbo::StreamsHelper
|
2
|
-
# Returns a new <tt>Turbo::Streams::TagBuilder</tt> object that accepts stream actions and renders them
|
2
|
+
# Returns a new <tt>Turbo::Streams::TagBuilder</tt> object that accepts stream actions and renders them as
|
3
3
|
# the template tags needed to send across the wire. This object is automatically yielded to turbo_stream.erb templates.
|
4
4
|
#
|
5
5
|
# When responding to HTTP requests, controllers can declare `turbo_stream` format response templates in that same
|
@@ -39,7 +39,9 @@ module Turbo::StreamsHelper
|
|
39
39
|
# The example above will process all turbo streams sent to a stream name like <tt>account:5:entries</tt>
|
40
40
|
# (when Current.account.id = 5). Updates to this stream can be sent like
|
41
41
|
# <tt>entry.broadcast_append_to entry.account, :entries, target: "entries"</tt>.
|
42
|
-
def turbo_stream_from(*streamables)
|
43
|
-
|
42
|
+
def turbo_stream_from(*streamables, **attributes)
|
43
|
+
attributes[:channel] = "Turbo::StreamsChannel"
|
44
|
+
attributes[:"signed-stream-name"] = Turbo::StreamsChannel.signed_stream_name(streamables)
|
45
|
+
tag.turbo_cable_stream_source(**attributes)
|
44
46
|
end
|
45
47
|
end
|
@@ -1,15 +1,18 @@
|
|
1
1
|
let consumer
|
2
2
|
|
3
3
|
export async function getConsumer() {
|
4
|
-
|
5
|
-
const { createConsumer } = await import("@rails/actioncable/src")
|
6
|
-
return setConsumer(createConsumer())
|
4
|
+
return consumer || setConsumer(createConsumer().then(setConsumer))
|
7
5
|
}
|
8
6
|
|
9
7
|
export function setConsumer(newConsumer) {
|
10
8
|
return consumer = newConsumer
|
11
9
|
}
|
12
10
|
|
11
|
+
export async function createConsumer() {
|
12
|
+
const { createConsumer } = await import(/* webpackChunkName: "actioncable" */ "@rails/actioncable/src")
|
13
|
+
return createConsumer()
|
14
|
+
}
|
15
|
+
|
13
16
|
export async function subscribeTo(channel, mixin) {
|
14
17
|
const { subscriptions } = await getConsumer()
|
15
18
|
return subscriptions.create(channel, mixin)
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# The job that powers all the <tt>broadcast_$action_later</tt> broadcasts available in <tt>Turbo::Streams::Broadcasts</tt>.
|
2
2
|
class Turbo::Streams::ActionBroadcastJob < ActiveJob::Base
|
3
|
+
discard_on ActiveJob::DeserializationError
|
4
|
+
|
3
5
|
def perform(stream, action:, target:, **rendering)
|
4
6
|
Turbo::StreamsChannel.broadcast_action_to stream, action: action, target: target, **rendering
|
5
7
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# The job that powers the <tt>broadcast_render_later_to</tt> available in <tt>Turbo::Streams::Broadcasts</tt> for rendering
|
2
2
|
# turbo stream templates.
|
3
3
|
class Turbo::Streams::BroadcastJob < ActiveJob::Base
|
4
|
+
discard_on ActiveJob::DeserializationError
|
5
|
+
|
4
6
|
def perform(stream, **rendering)
|
5
7
|
Turbo::StreamsChannel.broadcast_render_to stream, **rendering
|
6
8
|
end
|
@@ -39,7 +39,7 @@ module Turbo::Broadcastable
|
|
39
39
|
module ClassMethods
|
40
40
|
# Configures the model to broadcast creates, updates, and destroys to a stream name derived at runtime by the
|
41
41
|
# <tt>stream</tt> symbol invocation. By default, the creates are appended to a dom id target name derived from
|
42
|
-
# the model's plural name. The insertion can also be made to be a prepend by overwriting <tt>
|
42
|
+
# the model's plural name. The insertion can also be made to be a prepend by overwriting <tt>inserts_by</tt> and
|
43
43
|
# the target dom id overwritten by passing <tt>target</tt>. Examples:
|
44
44
|
#
|
45
45
|
# class Message < ApplicationRecord
|
@@ -52,14 +52,14 @@ module Turbo::Broadcastable
|
|
52
52
|
# broadcasts_to ->(message) { [ message.board, :messages ] }, inserts_by: :prepend, target: "board_messages"
|
53
53
|
# end
|
54
54
|
def broadcasts_to(stream, inserts_by: :append, target: broadcast_target_default)
|
55
|
-
after_create_commit -> { broadcast_action_later_to stream.try(:call, self) || send(stream), action: inserts_by, target: target }
|
55
|
+
after_create_commit -> { broadcast_action_later_to stream.try(:call, self) || send(stream), action: inserts_by, target: target.try(:call, self) || target }
|
56
56
|
after_update_commit -> { broadcast_replace_later_to stream.try(:call, self) || send(stream) }
|
57
57
|
after_destroy_commit -> { broadcast_remove_to stream.try(:call, self) || send(stream) }
|
58
58
|
end
|
59
59
|
|
60
60
|
# Same as <tt>#broadcasts_to</tt>, but the designated stream is automatically set to the current model.
|
61
61
|
def broadcasts(inserts_by: :append, target: broadcast_target_default)
|
62
|
-
after_create_commit -> { broadcast_action_later action: inserts_by, target: target }
|
62
|
+
after_create_commit -> { broadcast_action_later action: inserts_by, target: target.try(:call, self) || target }
|
63
63
|
after_update_commit -> { broadcast_replace_later }
|
64
64
|
after_destroy_commit -> { broadcast_remove }
|
65
65
|
end
|
@@ -75,8 +75,8 @@ module Turbo::Broadcastable
|
|
75
75
|
#
|
76
76
|
# # Sends <turbo-stream action="remove" target="clearance_5"></turbo-stream> to the stream named "identity:2:clearances"
|
77
77
|
# clearance.broadcast_remove_to examiner.identity, :clearances
|
78
|
-
def broadcast_remove_to(*streamables)
|
79
|
-
Turbo::StreamsChannel.broadcast_remove_to
|
78
|
+
def broadcast_remove_to(*streamables, target: self)
|
79
|
+
Turbo::StreamsChannel.broadcast_remove_to(*streamables, target: target)
|
80
80
|
end
|
81
81
|
|
82
82
|
# Same as <tt>#broadcast_remove_to</tt>, but the designated stream is automatically set to the current model.
|
@@ -95,7 +95,7 @@ module Turbo::Broadcastable
|
|
95
95
|
# # to the stream named "identity:2:clearances"
|
96
96
|
# clearance.broadcast_replace_to examiner.identity, :clearances, partial: "clearances/other_partial", locals: { a: 1 }
|
97
97
|
def broadcast_replace_to(*streamables, **rendering)
|
98
|
-
Turbo::StreamsChannel.broadcast_replace_to
|
98
|
+
Turbo::StreamsChannel.broadcast_replace_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering))
|
99
99
|
end
|
100
100
|
|
101
101
|
# Same as <tt>#broadcast_replace_to</tt>, but the designated stream is automatically set to the current model.
|
@@ -103,6 +103,57 @@ module Turbo::Broadcastable
|
|
103
103
|
broadcast_replace_to self, **rendering
|
104
104
|
end
|
105
105
|
|
106
|
+
# Update this broadcastable model in the dom for subscribers of the stream name identified by the passed
|
107
|
+
# <tt>streamables</tt>. The rendering parameters can be set by appending named arguments to the call. Examples:
|
108
|
+
#
|
109
|
+
# # Sends <turbo-stream action="update" target="clearance_5"><template><div id="clearance_5">My Clearance</div></template></turbo-stream>
|
110
|
+
# # to the stream named "identity:2:clearances"
|
111
|
+
# clearance.broadcast_update_to examiner.identity, :clearances
|
112
|
+
#
|
113
|
+
# # Sends <turbo-stream action="update" target="clearance_5"><template><div id="clearance_5">Other partial</div></template></turbo-stream>
|
114
|
+
# # to the stream named "identity:2:clearances"
|
115
|
+
# clearance.broadcast_update_to examiner.identity, :clearances, partial: "clearances/other_partial", locals: { a: 1 }
|
116
|
+
def broadcast_update_to(*streamables, **rendering)
|
117
|
+
Turbo::StreamsChannel.broadcast_update_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering))
|
118
|
+
end
|
119
|
+
|
120
|
+
# Same as <tt>#broadcast_update_to</tt>, but the designated stream is automatically set to the current model.
|
121
|
+
def broadcast_update(**rendering)
|
122
|
+
broadcast_update_to self, **rendering
|
123
|
+
end
|
124
|
+
|
125
|
+
# Insert a rendering of this broadcastable model before the target identified by it's dom id passed as <tt>target</tt>
|
126
|
+
# for subscribers of the stream name identified by the passed <tt>streamables</tt>. The rendering parameters can be set by
|
127
|
+
# appending named arguments to the call. Examples:
|
128
|
+
#
|
129
|
+
# # Sends <turbo-stream action="before" target="clearance_5"><template><div id="clearance_4">My Clearance</div></template></turbo-stream>
|
130
|
+
# # to the stream named "identity:2:clearances"
|
131
|
+
# clearance.broadcast_before_to examiner.identity, :clearances, target: "clearance_5"
|
132
|
+
#
|
133
|
+
# # Sends <turbo-stream action="before" target="clearance_5"><template><div id="clearance_4">Other partial</div></template></turbo-stream>
|
134
|
+
# # to the stream named "identity:2:clearances"
|
135
|
+
# clearance.broadcast_before_to examiner.identity, :clearances, target: "clearance_5",
|
136
|
+
# partial: "clearances/other_partial", locals: { a: 1 }
|
137
|
+
def broadcast_before_to(*streamables, target:, **rendering)
|
138
|
+
Turbo::StreamsChannel.broadcast_before_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
|
139
|
+
end
|
140
|
+
|
141
|
+
# Insert a rendering of this broadcastable model after the target identified by it's dom id passed as <tt>target</tt>
|
142
|
+
# for subscribers of the stream name identified by the passed <tt>streamables</tt>. The rendering parameters can be set by
|
143
|
+
# appending named arguments to the call. Examples:
|
144
|
+
#
|
145
|
+
# # Sends <turbo-stream action="after" target="clearance_5"><template><div id="clearance_6">My Clearance</div></template></turbo-stream>
|
146
|
+
# # to the stream named "identity:2:clearances"
|
147
|
+
# clearance.broadcast_after_to examiner.identity, :clearances, target: "clearance_5"
|
148
|
+
#
|
149
|
+
# # Sends <turbo-stream action="after" target="clearance_5"><template><div id="clearance_6">Other partial</div></template></turbo-stream>
|
150
|
+
# # to the stream named "identity:2:clearances"
|
151
|
+
# clearance.broadcast_after_to examiner.identity, :clearances, target: "clearance_5",
|
152
|
+
# partial: "clearances/other_partial", locals: { a: 1 }
|
153
|
+
def broadcast_after_to(*streamables, target:, **rendering)
|
154
|
+
Turbo::StreamsChannel.broadcast_after_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
|
155
|
+
end
|
156
|
+
|
106
157
|
# Append a rendering of this broadcastable model to the target identified by it's dom id passed as <tt>target</tt>
|
107
158
|
# for subscribers of the stream name identified by the passed <tt>streamables</tt>. The rendering parameters can be set by
|
108
159
|
# appending named arguments to the call. Examples:
|
@@ -116,7 +167,7 @@ module Turbo::Broadcastable
|
|
116
167
|
# clearance.broadcast_append_to examiner.identity, :clearances, target: "clearances",
|
117
168
|
# partial: "clearances/other_partial", locals: { a: 1 }
|
118
169
|
def broadcast_append_to(*streamables, target: broadcast_target_default, **rendering)
|
119
|
-
Turbo::StreamsChannel.broadcast_append_to
|
170
|
+
Turbo::StreamsChannel.broadcast_append_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
|
120
171
|
end
|
121
172
|
|
122
173
|
# Same as <tt>#broadcast_append_to</tt>, but the designated stream is automatically set to the current model.
|
@@ -137,10 +188,10 @@ module Turbo::Broadcastable
|
|
137
188
|
# clearance.broadcast_prepend_to examiner.identity, :clearances, target: "clearances",
|
138
189
|
# partial: "clearances/other_partial", locals: { a: 1 }
|
139
190
|
def broadcast_prepend_to(*streamables, target: broadcast_target_default, **rendering)
|
140
|
-
Turbo::StreamsChannel.broadcast_prepend_to
|
191
|
+
Turbo::StreamsChannel.broadcast_prepend_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
|
141
192
|
end
|
142
193
|
|
143
|
-
# Same as <tt>#
|
194
|
+
# Same as <tt>#broadcast_prepend_to</tt>, but the designated stream is automatically set to the current model.
|
144
195
|
def broadcast_prepend(target: broadcast_target_default, **rendering)
|
145
196
|
broadcast_prepend_to self, target: target, **rendering
|
146
197
|
end
|
@@ -162,7 +213,7 @@ module Turbo::Broadcastable
|
|
162
213
|
|
163
214
|
# Same as <tt>broadcast_replace_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
|
164
215
|
def broadcast_replace_later_to(*streamables, **rendering)
|
165
|
-
Turbo::StreamsChannel.broadcast_replace_later_to
|
216
|
+
Turbo::StreamsChannel.broadcast_replace_later_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering))
|
166
217
|
end
|
167
218
|
|
168
219
|
# Same as <tt>#broadcast_replace_later_to</tt>, but the designated stream is automatically set to the current model.
|
@@ -170,9 +221,19 @@ module Turbo::Broadcastable
|
|
170
221
|
broadcast_replace_later_to self, **rendering
|
171
222
|
end
|
172
223
|
|
224
|
+
# Same as <tt>broadcast_update_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
|
225
|
+
def broadcast_update_later_to(*streamables, **rendering)
|
226
|
+
Turbo::StreamsChannel.broadcast_update_later_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering))
|
227
|
+
end
|
228
|
+
|
229
|
+
# Same as <tt>#broadcast_update_later_to</tt>, but the designated stream is automatically set to the current model.
|
230
|
+
def broadcast_update_later(**rendering)
|
231
|
+
broadcast_update_later_to self, **rendering
|
232
|
+
end
|
233
|
+
|
173
234
|
# Same as <tt>broadcast_append_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
|
174
235
|
def broadcast_append_later_to(*streamables, target: broadcast_target_default, **rendering)
|
175
|
-
Turbo::StreamsChannel.broadcast_append_later_to
|
236
|
+
Turbo::StreamsChannel.broadcast_append_later_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
|
176
237
|
end
|
177
238
|
|
178
239
|
# Same as <tt>#broadcast_append_later_to</tt>, but the designated stream is automatically set to the current model.
|
@@ -182,7 +243,7 @@ module Turbo::Broadcastable
|
|
182
243
|
|
183
244
|
# Same as <tt>broadcast_prepend_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
|
184
245
|
def broadcast_prepend_later_to(*streamables, target: broadcast_target_default, **rendering)
|
185
|
-
Turbo::StreamsChannel.broadcast_prepend_later_to
|
246
|
+
Turbo::StreamsChannel.broadcast_prepend_later_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
|
186
247
|
end
|
187
248
|
|
188
249
|
# Same as <tt>#broadcast_prepend_later_to</tt>, but the designated stream is automatically set to the current model.
|
@@ -190,7 +251,7 @@ module Turbo::Broadcastable
|
|
190
251
|
broadcast_prepend_later_to self, target: target, **rendering
|
191
252
|
end
|
192
253
|
|
193
|
-
# Same as <tt>
|
254
|
+
# Same as <tt>broadcast_action_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
|
194
255
|
def broadcast_action_later_to(*streamables, action:, target: broadcast_target_default, **rendering)
|
195
256
|
Turbo::StreamsChannel.broadcast_action_later_to(*streamables, action: action, target: target, **broadcast_rendering_with_defaults(rendering))
|
196
257
|
end
|
@@ -219,10 +280,10 @@ module Turbo::Broadcastable
|
|
219
280
|
broadcast_render_later_to self, **rendering
|
220
281
|
end
|
221
282
|
|
222
|
-
# Same as <tt>
|
283
|
+
# Same as <tt>broadcast_render_later</tt> but run with the added option of naming the stream using the passed
|
223
284
|
# <tt>streamables</tt>.
|
224
285
|
def broadcast_render_later_to(*streamables, **rendering)
|
225
|
-
Turbo::StreamsChannel.broadcast_render_later_to
|
286
|
+
Turbo::StreamsChannel.broadcast_render_later_to(*streamables, **broadcast_rendering_with_defaults(rendering))
|
226
287
|
end
|
227
288
|
|
228
289
|
|
@@ -233,7 +294,9 @@ module Turbo::Broadcastable
|
|
233
294
|
|
234
295
|
def broadcast_rendering_with_defaults(options)
|
235
296
|
options.tap do |o|
|
236
|
-
|
297
|
+
# Add the current instance into the locals with the element name (which is the un-namespaced name)
|
298
|
+
# as the key. This parallels how the ActionView::ObjectRenderer would create a local variable.
|
299
|
+
o[:locals] = (o[:locals] || {}).reverse_merge!(model_name.element.to_sym => self)
|
237
300
|
o[:partial] ||= to_partial_path
|
238
301
|
end
|
239
302
|
end
|
@@ -40,6 +40,16 @@ class Turbo::Streams::TagBuilder
|
|
40
40
|
action :remove, target, allow_inferred_rendering: false
|
41
41
|
end
|
42
42
|
|
43
|
+
# Removes the <tt>targets</tt> from the dom. The targets can either be a CSS selector string or an object that responds to
|
44
|
+
# <tt>to_key</tt>, which is then called and passed through <tt>ActionView::RecordIdentifier.dom_id</tt> (all Active Records
|
45
|
+
# do). Examples:
|
46
|
+
#
|
47
|
+
# <%= turbo_stream.remove_all ".clearance_item" %>
|
48
|
+
# <%= turbo_stream.remove_all clearance %>
|
49
|
+
def remove_all(targets)
|
50
|
+
action_all :remove, targets, allow_inferred_rendering: false
|
51
|
+
end
|
52
|
+
|
43
53
|
# Replace the <tt>target</tt> in the dom with the either the <tt>content</tt> passed in, a rendering result determined
|
44
54
|
# by the <tt>rendering</tt> keyword arguments, the content in the block, or the rendering of the target as a record. Examples:
|
45
55
|
#
|
@@ -53,6 +63,71 @@ class Turbo::Streams::TagBuilder
|
|
53
63
|
action :replace, target, content, **rendering, &block
|
54
64
|
end
|
55
65
|
|
66
|
+
# Replace the <tt>targets</tt> in the dom with the either the <tt>content</tt> passed in, a rendering result determined
|
67
|
+
# by the <tt>rendering</tt> keyword arguments, the content in the block, or the rendering of the target as a record. Examples:
|
68
|
+
#
|
69
|
+
# <%= turbo_stream.replace_all ".clearance_item", "<div class='clearance_item'>Replace the dom target identified by the class clearance_item</div>" %>
|
70
|
+
# <%= turbo_stream.replace_all clearance %>
|
71
|
+
# <%= turbo_stream.replace_all clearance, partial: "clearances/clearance", locals: { title: "Hello" } %>
|
72
|
+
# <%= turbo_stream.replace_all ".clearance_item" do %>
|
73
|
+
# <div class='.clearance_item'>Replace the dom target identified by the class clearance_item</div>
|
74
|
+
# <% end %>
|
75
|
+
def replace_all(targets, content = nil, **rendering, &block)
|
76
|
+
action_all :replace, targets, content, **rendering, &block
|
77
|
+
end
|
78
|
+
|
79
|
+
# Insert the <tt>content</tt> passed in, a rendering result determined by the <tt>rendering</tt> keyword arguments,
|
80
|
+
# the content in the block, or the rendering of the target as a record before the <tt>target</tt> in the dom. Examples:
|
81
|
+
#
|
82
|
+
# <%= turbo_stream.before "clearance_5", "<div id='clearance_4'>Insert before the dom target identified by clearance_5</div>" %>
|
83
|
+
# <%= turbo_stream.before clearance %>
|
84
|
+
# <%= turbo_stream.before clearance, partial: "clearances/clearance", locals: { title: "Hello" } %>
|
85
|
+
# <%= turbo_stream.before "clearance_5" do %>
|
86
|
+
# <div id='clearance_4'>Insert before the dom target identified by clearance_5</div>
|
87
|
+
# <% end %>
|
88
|
+
def before(target, content = nil, **rendering, &block)
|
89
|
+
action :before, target, content, **rendering, &block
|
90
|
+
end
|
91
|
+
|
92
|
+
# Insert the <tt>content</tt> passed in, a rendering result determined by the <tt>rendering</tt> keyword arguments,
|
93
|
+
# the content in the block, or the rendering of the target as a record before the <tt>targets</tt> in the dom. Examples:
|
94
|
+
#
|
95
|
+
# <%= turbo_stream.before_all ".clearance_item", "<div class='clearance_item'>Insert before the dom target identified by the class clearance_item</div>" %>
|
96
|
+
# <%= turbo_stream.before_all clearance %>
|
97
|
+
# <%= turbo_stream.before_all clearance, partial: "clearances/clearance", locals: { title: "Hello" } %>
|
98
|
+
# <%= turbo_stream.before_all ".clearance_item" do %>
|
99
|
+
# <div class='clearance_item'>Insert before the dom target identified by clearance_item</div>
|
100
|
+
# <% end %>
|
101
|
+
def before_all(targets, content = nil, **rendering, &block)
|
102
|
+
action_all :before, targets, content, **rendering, &block
|
103
|
+
end
|
104
|
+
|
105
|
+
# Insert the <tt>content</tt> passed in, a rendering result determined by the <tt>rendering</tt> keyword arguments,
|
106
|
+
# the content in the block, or the rendering of the target as a record after the <tt>target</tt> in the dom. Examples:
|
107
|
+
#
|
108
|
+
# <%= turbo_stream.after "clearance_5", "<div id='clearance_6'>Insert after the dom target identified by clearance_5</div>" %>
|
109
|
+
# <%= turbo_stream.after clearance %>
|
110
|
+
# <%= turbo_stream.after clearance, partial: "clearances/clearance", locals: { title: "Hello" } %>
|
111
|
+
# <%= turbo_stream.after "clearance_5" do %>
|
112
|
+
# <div id='clearance_6'>Insert after the dom target identified by clearance_5</div>
|
113
|
+
# <% end %>
|
114
|
+
def after(target, content = nil, **rendering, &block)
|
115
|
+
action :after, target, content, **rendering, &block
|
116
|
+
end
|
117
|
+
|
118
|
+
# Insert the <tt>content</tt> passed in, a rendering result determined by the <tt>rendering</tt> keyword arguments,
|
119
|
+
# the content in the block, or the rendering of the target as a record after the <tt>targets</tt> in the dom. Examples:
|
120
|
+
#
|
121
|
+
# <%= turbo_stream.after_all ".clearance_item", "<div class='clearance_item'>Insert after the dom target identified by the class clearance_item</div>" %>
|
122
|
+
# <%= turbo_stream.after_all clearance %>
|
123
|
+
# <%= turbo_stream.after_all clearance, partial: "clearances/clearance", locals: { title: "Hello" } %>
|
124
|
+
# <%= turbo_stream.after_all "clearance_item" do %>
|
125
|
+
# <div class='clearance_item'>Insert after the dom target identified by the class clearance_item</div>
|
126
|
+
# <% end %>
|
127
|
+
def after_all(targets, content = nil, **rendering, &block)
|
128
|
+
action_all :after, targets, content, **rendering, &block
|
129
|
+
end
|
130
|
+
|
56
131
|
# Update the <tt>target</tt> in the dom with the either the <tt>content</tt> passed in or a rendering result determined
|
57
132
|
# by the <tt>rendering</tt> keyword arguments, the content in the block, or the rendering of the target as a record. Examples:
|
58
133
|
#
|
@@ -66,6 +141,19 @@ class Turbo::Streams::TagBuilder
|
|
66
141
|
action :update, target, content, **rendering, &block
|
67
142
|
end
|
68
143
|
|
144
|
+
# Update the <tt>targets</tt> in the dom with the either the <tt>content</tt> passed in or a rendering result determined
|
145
|
+
# by the <tt>rendering</tt> keyword arguments, the content in the block, or the rendering of the targets as a record. Examples:
|
146
|
+
#
|
147
|
+
# <%= turbo_stream.update_all "clearance_item", "Update the content of the dom target identified by the class clearance_item" %>
|
148
|
+
# <%= turbo_stream.update_all clearance %>
|
149
|
+
# <%= turbo_stream.update_all clearance, partial: "clearances/new_clearance", locals: { title: "Hello" } %>
|
150
|
+
# <%= turbo_stream.update_all "clearance_item" do %>
|
151
|
+
# Update the content of the dom target identified by the class clearance_item
|
152
|
+
# <% end %>
|
153
|
+
def update_all(targets, content = nil, **rendering, &block)
|
154
|
+
action_all :update, targets, content, **rendering, &block
|
155
|
+
end
|
156
|
+
|
69
157
|
# Append to the target in the dom identified with <tt>target</tt> either the <tt>content</tt> passed in or a
|
70
158
|
# rendering result determined by the <tt>rendering</tt> keyword arguments, the content in the block,
|
71
159
|
# or the rendering of the content as a record. Examples:
|
@@ -80,6 +168,20 @@ class Turbo::Streams::TagBuilder
|
|
80
168
|
action :append, target, content, **rendering, &block
|
81
169
|
end
|
82
170
|
|
171
|
+
# Append to the targets in the dom identified with <tt>targets</tt> either the <tt>content</tt> passed in or a
|
172
|
+
# rendering result determined by the <tt>rendering</tt> keyword arguments, the content in the block,
|
173
|
+
# or the rendering of the content as a record. Examples:
|
174
|
+
#
|
175
|
+
# <%= turbo_stream.append_all ".clearances", "<div class='clearance_item'>Append this to .clearance_group</div>" %>
|
176
|
+
# <%= turbo_stream.append_all ".clearances", clearance %>
|
177
|
+
# <%= turbo_stream.append_all ".clearances", partial: "clearances/new_clearance", locals: { clearance: clearance } %>
|
178
|
+
# <%= turbo_stream.append_all ".clearances" do %>
|
179
|
+
# <div id='clearance_item'>Append this to .clearances</div>
|
180
|
+
# <% end %>
|
181
|
+
def append_all(targets, content = nil, **rendering, &block)
|
182
|
+
action_all :append, targets, content, **rendering, &block
|
183
|
+
end
|
184
|
+
|
83
185
|
# Prepend to the target in the dom identified with <tt>target</tt> either the <tt>content</tt> passed in or a
|
84
186
|
# rendering result determined by the <tt>rendering</tt> keyword arguments or the content in the block,
|
85
187
|
# or the rendering of the content as a record. Examples:
|
@@ -94,28 +196,45 @@ class Turbo::Streams::TagBuilder
|
|
94
196
|
action :prepend, target, content, **rendering, &block
|
95
197
|
end
|
96
198
|
|
97
|
-
#
|
199
|
+
# Prepend to the targets in the dom identified with <tt>targets</tt> either the <tt>content</tt> passed in or a
|
200
|
+
# rendering result determined by the <tt>rendering</tt> keyword arguments or the content in the block,
|
201
|
+
# or the rendering of the content as a record. Examples:
|
202
|
+
#
|
203
|
+
# <%= turbo_stream.prepend_all ".clearances", "<div class='clearance_item'>Prepend this to .clearances</div>" %>
|
204
|
+
# <%= turbo_stream.prepend_all ".clearances", clearance %>
|
205
|
+
# <%= turbo_stream.prepend_all ".clearances", partial: "clearances/new_clearance", locals: { clearance: clearance } %>
|
206
|
+
# <%= turbo_stream.prepend_all ".clearances" do %>
|
207
|
+
# <div class='clearance_item'>Prepend this to .clearances</div>
|
208
|
+
# <% end %>
|
209
|
+
def prepend_all(targets, content = nil, **rendering, &block)
|
210
|
+
action_all :prepend, targets, content, **rendering, &block
|
211
|
+
end
|
212
|
+
|
213
|
+
# Send an action of the type <tt>name</tt> to <tt>target</tt>. Options described in the concrete methods.
|
98
214
|
def action(name, target, content = nil, allow_inferred_rendering: true, **rendering, &block)
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
turbo_stream_action_tag name, target: target_name, template: (render_record(target) if allow_inferred_rendering)
|
110
|
-
end
|
215
|
+
template = render_template(target, content, allow_inferred_rendering: allow_inferred_rendering, **rendering, &block)
|
216
|
+
|
217
|
+
turbo_stream_action_tag name, target: target, template: template
|
218
|
+
end
|
219
|
+
|
220
|
+
# Send an action of the type <tt>name</tt> to <tt>targets</tt>. Options described in the concrete methods.
|
221
|
+
def action_all(name, targets, content = nil, allow_inferred_rendering: true, **rendering, &block)
|
222
|
+
template = render_template(targets, content, allow_inferred_rendering: allow_inferred_rendering, **rendering, &block)
|
223
|
+
|
224
|
+
turbo_stream_action_tag name, targets: targets, template: template
|
111
225
|
end
|
112
226
|
|
113
227
|
private
|
114
|
-
def
|
115
|
-
|
116
|
-
|
228
|
+
def render_template(target, content = nil, allow_inferred_rendering: true, **rendering, &block)
|
229
|
+
case
|
230
|
+
when content
|
231
|
+
allow_inferred_rendering ? (render_record(content) || content) : content
|
232
|
+
when block_given?
|
233
|
+
@view_context.capture(&block)
|
234
|
+
when rendering.any?
|
235
|
+
@view_context.render(formats: [ :html ], **rendering)
|
117
236
|
else
|
118
|
-
target
|
237
|
+
render_record(target) if allow_inferred_rendering
|
119
238
|
end
|
120
239
|
end
|
121
240
|
|
@@ -0,0 +1,9 @@
|
|
1
|
+
if (cable_config_path = Rails.root.join("config/cable.yml")).exist?
|
2
|
+
say "Enable redis in bundle"
|
3
|
+
uncomment_lines "Gemfile", /gem ['"]redis['"]/
|
4
|
+
|
5
|
+
say "Switch development cable to use redis"
|
6
|
+
gsub_file cable_config_path.to_s, /development:\n\s+adapter: async/, "development:\n adapter: redis\n url: redis://localhost:6379/1"
|
7
|
+
else
|
8
|
+
say 'ActionCable config file (config/cable.yml) is missing. Uncomment "gem \'redis\'" in your Gemfile and create config/cable.yml to use the Turbo Streams broadcast feature.'
|
9
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
if (js_entrypoint_path = Rails.root.join("app/javascript/application.js")).exist?
|
2
|
+
say "Import Turbo"
|
3
|
+
append_to_file "app/javascript/application.js", %(import "@hotwired/turbo-rails"\n)
|
4
|
+
else
|
5
|
+
say "You must import @hotwired/turbo-rails in your JavaScript entrypoint file", :red
|
6
|
+
end
|
7
|
+
|
8
|
+
say "Install Turbo"
|
9
|
+
run "yarn add @hotwired/turbo-rails"
|