turbo-rails 1.5.0 → 2.0.4
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 +15 -11
 - data/app/assets/javascripts/turbo.js +1896 -726
 - data/app/assets/javascripts/turbo.min.js +9 -5
 - data/app/assets/javascripts/turbo.min.js.map +1 -1
 - data/app/channels/turbo/streams/broadcasts.rb +19 -5
 - data/app/controllers/concerns/turbo/request_id_tracking.rb +12 -0
 - data/app/controllers/turbo/frames/frame_request.rb +2 -2
 - data/app/controllers/turbo/native/navigation.rb +6 -3
 - data/app/helpers/turbo/drive_helper.rb +72 -14
 - data/app/helpers/turbo/frames_helper.rb +8 -8
 - data/app/helpers/turbo/streams/action_helper.rb +9 -2
 - data/app/helpers/turbo/streams_helper.rb +0 -1
 - data/app/javascript/turbo/index.js +2 -0
 - data/app/jobs/turbo/streams/action_broadcast_job.rb +2 -2
 - data/app/jobs/turbo/streams/broadcast_job.rb +1 -1
 - data/app/jobs/turbo/streams/broadcast_stream_job.rb +7 -0
 - data/app/models/concerns/turbo/broadcastable.rb +175 -34
 - data/app/models/turbo/debouncer.rb +24 -0
 - data/app/models/turbo/streams/tag_builder.rb +20 -0
 - data/app/models/turbo/thread_debouncer.rb +28 -0
 - data/config/routes.rb +0 -1
 - data/lib/install/turbo_with_importmap.rb +1 -1
 - data/lib/turbo/broadcastable/test_helper.rb +5 -5
 - data/lib/turbo/engine.rb +13 -2
 - data/lib/turbo/test_assertions/integration_test_assertions.rb +2 -2
 - data/lib/turbo/test_assertions.rb +2 -2
 - data/lib/turbo/version.rb +1 -1
 - data/lib/turbo-rails.rb +10 -0
 - metadata +6 -2
 
| 
         @@ -14,8 +14,8 @@ 
     | 
|
| 
       14 
14 
     | 
    
         
             
            #       end
         
     | 
| 
       15 
15 
     | 
    
         
             
            #   end
         
     | 
| 
       16 
16 
     | 
    
         
             
            #
         
     | 
| 
       17 
     | 
    
         
            -
            # This is an example from [ 
     | 
| 
       18 
     | 
    
         
            -
            #  
     | 
| 
      
 17 
     | 
    
         
            +
            # This is an example from {HEY}[https://hey.com], and the clearance is the model that drives
         
     | 
| 
      
 18 
     | 
    
         
            +
            # {the screener}[https://hey.com/features/the-screener/], which gives users the power to deny first-time senders (petitioners)
         
     | 
| 
       19 
19 
     | 
    
         
             
            # access to their attention (as the examiner). When a new clearance is created upon receipt of an email from a first-time
         
     | 
| 
       20 
20 
     | 
    
         
             
            # sender, that'll trigger the call to broadcast_later, which in turn invokes <tt>broadcast_prepend_later_to</tt>.
         
     | 
| 
       21 
21 
     | 
    
         
             
            #
         
     | 
| 
         @@ -27,7 +27,7 @@ 
     | 
|
| 
       27 
27 
     | 
    
         
             
            # (which is derived by default from the plural model name of the model, but can be overwritten).
         
     | 
| 
       28 
28 
     | 
    
         
             
            #
         
     | 
| 
       29 
29 
     | 
    
         
             
            # You can also choose to render html instead of a partial inside of a broadcast
         
     | 
| 
       30 
     | 
    
         
            -
            # you do this by passing the  
     | 
| 
      
 30 
     | 
    
         
            +
            # you do this by passing the +html:+ option to any broadcast method that accepts the **rendering argument. Example:
         
     | 
| 
       31 
31 
     | 
    
         
             
            #
         
     | 
| 
       32 
32 
     | 
    
         
             
            #   class Message < ApplicationRecord
         
     | 
| 
       33 
33 
     | 
    
         
             
            #     belongs_to :user
         
     | 
| 
         @@ -40,8 +40,8 @@ 
     | 
|
| 
       40 
40 
     | 
    
         
             
            #       end
         
     | 
| 
       41 
41 
     | 
    
         
             
            #   end
         
     | 
| 
       42 
42 
     | 
    
         
             
            #
         
     | 
| 
       43 
     | 
    
         
            -
            # If you want to render a template instead of a partial, e.g. ('messages/index' or 'messages/show'), you can use the  
     | 
| 
       44 
     | 
    
         
            -
            # Again, only to any broadcast method that accepts the  
     | 
| 
      
 43 
     | 
    
         
            +
            # If you want to render a template instead of a partial, e.g. ('messages/index' or 'messages/show'), you can use the +template:+ option.
         
     | 
| 
      
 44 
     | 
    
         
            +
            # Again, only to any broadcast method that accepts the +**rendering+ argument. Example:
         
     | 
| 
       45 
45 
     | 
    
         
             
            #
         
     | 
| 
       46 
46 
     | 
    
         
             
            #   class Message < ApplicationRecord
         
     | 
| 
       47 
47 
     | 
    
         
             
            #     belongs_to :user
         
     | 
| 
         @@ -54,7 +54,7 @@ 
     | 
|
| 
       54 
54 
     | 
    
         
             
            #       end
         
     | 
| 
       55 
55 
     | 
    
         
             
            #   end
         
     | 
| 
       56 
56 
     | 
    
         
             
            #
         
     | 
| 
       57 
     | 
    
         
            -
            # If you want to render a renderable object you can use the  
     | 
| 
      
 57 
     | 
    
         
            +
            # If you want to render a renderable object you can use the +renderable:+ option.
         
     | 
| 
       58 
58 
     | 
    
         
             
            #
         
     | 
| 
       59 
59 
     | 
    
         
             
            #   class Message < ApplicationRecord
         
     | 
| 
       60 
60 
     | 
    
         
             
            #     belongs_to :user
         
     | 
| 
         @@ -67,17 +67,99 @@ 
     | 
|
| 
       67 
67 
     | 
    
         
             
            #       end
         
     | 
| 
       68 
68 
     | 
    
         
             
            #   end
         
     | 
| 
       69 
69 
     | 
    
         
             
            #
         
     | 
| 
       70 
     | 
    
         
            -
            # There are  
     | 
| 
       71 
     | 
    
         
            -
            # <tt>prepend</tt 
     | 
| 
      
 70 
     | 
    
         
            +
            # There are seven basic actions you can broadcast: <tt>after</tt>, <tt>append</tt>, <tt>before</tt>,
         
     | 
| 
      
 71 
     | 
    
         
            +
            # <tt>prepend</tt>, <tt>remove</tt>, <tt>replace</tt>, and
         
     | 
| 
      
 72 
     | 
    
         
            +
            # <tt>update</tt>. As a rule, you should use the <tt>_later</tt> versions of everything except for remove when broadcasting
         
     | 
| 
       72 
73 
     | 
    
         
             
            # within a real-time path, like a controller or model, since all those updates require a rendering step, which can slow down
         
     | 
| 
       73 
74 
     | 
    
         
             
            # execution. You don't need to do this for remove, since only the dom id for the model is used.
         
     | 
| 
       74 
75 
     | 
    
         
             
            #
         
     | 
| 
       75 
     | 
    
         
            -
            # In addition to the  
     | 
| 
      
 76 
     | 
    
         
            +
            # In addition to the seven basic actions, you can also use <tt>broadcast_render</tt>,
         
     | 
| 
       76 
77 
     | 
    
         
             
            # <tt>broadcast_render_to</tt> <tt>broadcast_render_later</tt>, and <tt>broadcast_render_later_to</tt>
         
     | 
| 
       77 
78 
     | 
    
         
             
            # to render a turbo stream template with multiple actions.
         
     | 
| 
      
 79 
     | 
    
         
            +
            #
         
     | 
| 
      
 80 
     | 
    
         
            +
            # == Page refreshes
         
     | 
| 
      
 81 
     | 
    
         
            +
            #
         
     | 
| 
      
 82 
     | 
    
         
            +
            # You can broadcast "page refresh" stream actions. This will make subscribed clients reload the 
         
     | 
| 
      
 83 
     | 
    
         
            +
            # page. For pages that configure morphing and scroll preservation, this will translate into smooth
         
     | 
| 
      
 84 
     | 
    
         
            +
            # updates when it only updates the content that changed.
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            # This approach is an alternative to fine-grained stream actions targeting specific DOM elements. It
         
     | 
| 
      
 87 
     | 
    
         
            +
            # offers good fidelity with a much simpler programming model. As a tradeoff, the fidelity you can reach
         
     | 
| 
      
 88 
     | 
    
         
            +
            # is often not as high as with targeted stream actions since it renders the entire page again.
         
     | 
| 
      
 89 
     | 
    
         
            +
            #
         
     | 
| 
      
 90 
     | 
    
         
            +
            # The +broadcast_refreshes+ class method configures the model to broadcast a "page refresh" on creates, 
         
     | 
| 
      
 91 
     | 
    
         
            +
            # updates, and destroys to a stream name derived at runtime by the <tt>stream</tt> symbol invocation. Examples
         
     | 
| 
      
 92 
     | 
    
         
            +
            #
         
     | 
| 
      
 93 
     | 
    
         
            +
            #   class Board < ApplicationRecord
         
     | 
| 
      
 94 
     | 
    
         
            +
            #     broadcast_refreshes
         
     | 
| 
      
 95 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 96 
     | 
    
         
            +
            #
         
     | 
| 
      
 97 
     | 
    
         
            +
            # In this example, when a board is created, updated, or destroyed, a Turbo Stream for a
         
     | 
| 
      
 98 
     | 
    
         
            +
            # page refresh will be broadcasted to all clients subscribed to the "boards" stream.
         
     | 
| 
      
 99 
     | 
    
         
            +
            #
         
     | 
| 
      
 100 
     | 
    
         
            +
            # This works great in hierarchical structures, where the child record touches parent records automatically
         
     | 
| 
      
 101 
     | 
    
         
            +
            # to invalidate the cache:
         
     | 
| 
      
 102 
     | 
    
         
            +
            #
         
     | 
| 
      
 103 
     | 
    
         
            +
            #   class Column < ApplicationRecord
         
     | 
| 
      
 104 
     | 
    
         
            +
            #     belongs_to :board, touch: true # +Board+ will trigger a page refresh on column changes
         
     | 
| 
      
 105 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 106 
     | 
    
         
            +
            #
         
     | 
| 
      
 107 
     | 
    
         
            +
            # You can also specify the streamable declaratively by passing a symbol to the +broadcast_refreshes_to+ method:
         
     | 
| 
      
 108 
     | 
    
         
            +
            #
         
     | 
| 
      
 109 
     | 
    
         
            +
            #   class Column < ApplicationRecord
         
     | 
| 
      
 110 
     | 
    
         
            +
            #     belongs_to :board
         
     | 
| 
      
 111 
     | 
    
         
            +
            #     broadcast_refreshes_to :board
         
     | 
| 
      
 112 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 113 
     | 
    
         
            +
            #
         
     | 
| 
      
 114 
     | 
    
         
            +
            # For more granular control, you can also broadcast a "page refresh" to a stream name derived 
         
     | 
| 
      
 115 
     | 
    
         
            +
            # from the passed <tt>streamables</tt> by using the instance-level methods <tt>broadcast_refresh_to</tt> or
         
     | 
| 
      
 116 
     | 
    
         
            +
            # <tt>broadcast_refresh_later_to</tt>. These methods are particularly useful when you want to trigger 
         
     | 
| 
      
 117 
     | 
    
         
            +
            # a page refresh for more specific scenarios. Example:
         
     | 
| 
      
 118 
     | 
    
         
            +
            #
         
     | 
| 
      
 119 
     | 
    
         
            +
            #   class Clearance < ApplicationRecord
         
     | 
| 
      
 120 
     | 
    
         
            +
            #     belongs_to :petitioner, class_name: "Contact"
         
     | 
| 
      
 121 
     | 
    
         
            +
            #     belongs_to :examiner,   class_name: "User"
         
     | 
| 
      
 122 
     | 
    
         
            +
            #
         
     | 
| 
      
 123 
     | 
    
         
            +
            #     after_create_commit :broadcast_refresh_later
         
     | 
| 
      
 124 
     | 
    
         
            +
            #
         
     | 
| 
      
 125 
     | 
    
         
            +
            #     private
         
     | 
| 
      
 126 
     | 
    
         
            +
            #       def broadcast_refresh_later
         
     | 
| 
      
 127 
     | 
    
         
            +
            #         broadcast_refresh_later_to examiner.identity, :clearances
         
     | 
| 
      
 128 
     | 
    
         
            +
            #       end
         
     | 
| 
      
 129 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 130 
     | 
    
         
            +
            #
         
     | 
| 
      
 131 
     | 
    
         
            +
            # In this example, a "page refresh" is broadcast to the stream named "identity:<identity-id>:clearances" 
         
     | 
| 
      
 132 
     | 
    
         
            +
            # after a new clearance is created. All clients subscribed to this stream will refresh the page to reflect
         
     | 
| 
      
 133 
     | 
    
         
            +
            # the changes.
         
     | 
| 
      
 134 
     | 
    
         
            +
            #
         
     | 
| 
      
 135 
     | 
    
         
            +
            # When broadcasting page refreshes, Turbo will automatically debounce multiple calls in a row to only broadcast the last one. 
         
     | 
| 
      
 136 
     | 
    
         
            +
            # This is meant for scenarios where you process records in mass. Because of the nature of such signals, it makes no sense to
         
     | 
| 
      
 137 
     | 
    
         
            +
            # broadcast them repeatedly and individually.
         
     | 
| 
      
 138 
     | 
    
         
            +
            # == Suppressing broadcasts
         
     | 
| 
      
 139 
     | 
    
         
            +
            #
         
     | 
| 
      
 140 
     | 
    
         
            +
            # Sometimes, you need to disable broadcasts in certain scenarios. You can use <tt>.suppressing_turbo_broadcasts</tt> to create
         
     | 
| 
      
 141 
     | 
    
         
            +
            # execution contexts where broadcasts are disabled:
         
     | 
| 
      
 142 
     | 
    
         
            +
            #
         
     | 
| 
      
 143 
     | 
    
         
            +
            #   class Message < ApplicationRecord
         
     | 
| 
      
 144 
     | 
    
         
            +
            #     after_create_commit :update_message
         
     | 
| 
      
 145 
     | 
    
         
            +
            #
         
     | 
| 
      
 146 
     | 
    
         
            +
            #     private
         
     | 
| 
      
 147 
     | 
    
         
            +
            #       def update_message
         
     | 
| 
      
 148 
     | 
    
         
            +
            #         broadcast_replace_to(user, :message, target: "message", renderable: MessageComponent.new)
         
     | 
| 
      
 149 
     | 
    
         
            +
            #       end
         
     | 
| 
      
 150 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 151 
     | 
    
         
            +
            #
         
     | 
| 
      
 152 
     | 
    
         
            +
            #   Message.suppressing_turbo_broadcasts do
         
     | 
| 
      
 153 
     | 
    
         
            +
            #     Message.create!(board: board) # This won't broadcast the replace action
         
     | 
| 
      
 154 
     | 
    
         
            +
            #   end
         
     | 
| 
       78 
155 
     | 
    
         
             
            module Turbo::Broadcastable
         
     | 
| 
       79 
156 
     | 
    
         
             
              extend ActiveSupport::Concern
         
     | 
| 
       80 
157 
     | 
    
         | 
| 
      
 158 
     | 
    
         
            +
              included do
         
     | 
| 
      
 159 
     | 
    
         
            +
                thread_mattr_accessor :suppressed_turbo_broadcasts, instance_accessor: false
         
     | 
| 
      
 160 
     | 
    
         
            +
                delegate :suppressed_turbo_broadcasts?, to: "self.class"
         
     | 
| 
      
 161 
     | 
    
         
            +
              end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
       81 
163 
     | 
    
         
             
              module ClassMethods
         
     | 
| 
       82 
164 
     | 
    
         
             
                # Configures the model to broadcast creates, updates, and destroys to a stream name derived at runtime by the
         
     | 
| 
       83 
165 
     | 
    
         
             
                # <tt>stream</tt> symbol invocation. By default, the creates are appended to a dom id target name derived from
         
     | 
| 
         @@ -112,10 +194,46 @@ module Turbo::Broadcastable 
     | 
|
| 
       112 
194 
     | 
    
         
             
                  after_destroy_commit -> { broadcast_remove }
         
     | 
| 
       113 
195 
     | 
    
         
             
                end
         
     | 
| 
       114 
196 
     | 
    
         | 
| 
      
 197 
     | 
    
         
            +
                # Configures the model to broadcast a "page refresh" on creates, updates, and destroys to a stream
         
     | 
| 
      
 198 
     | 
    
         
            +
                # name derived at runtime by the <tt>stream</tt> symbol invocation. Examples:
         
     | 
| 
      
 199 
     | 
    
         
            +
                #
         
     | 
| 
      
 200 
     | 
    
         
            +
                #   class Message < ApplicationRecord
         
     | 
| 
      
 201 
     | 
    
         
            +
                #     belongs_to :board
         
     | 
| 
      
 202 
     | 
    
         
            +
                #     broadcasts_refreshes_to :board
         
     | 
| 
      
 203 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 204 
     | 
    
         
            +
                #
         
     | 
| 
      
 205 
     | 
    
         
            +
                #   class Message < ApplicationRecord
         
     | 
| 
      
 206 
     | 
    
         
            +
                #     belongs_to :board
         
     | 
| 
      
 207 
     | 
    
         
            +
                #     broadcasts_refreshes_to ->(message) { [ message.board, :messages ] }
         
     | 
| 
      
 208 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 209 
     | 
    
         
            +
                def broadcasts_refreshes_to(stream)
         
     | 
| 
      
 210 
     | 
    
         
            +
                  after_commit -> { broadcast_refresh_later_to(stream.try(:call, self) || send(stream)) }
         
     | 
| 
      
 211 
     | 
    
         
            +
                end
         
     | 
| 
      
 212 
     | 
    
         
            +
             
     | 
| 
      
 213 
     | 
    
         
            +
                # Same as <tt>#broadcasts_refreshes_to</tt>, but the designated stream for page refreshes is automatically set to
         
     | 
| 
      
 214 
     | 
    
         
            +
                # the current model, for creates - to the model plural name, which can be overriden by passing <tt>stream</tt>.
         
     | 
| 
      
 215 
     | 
    
         
            +
                def broadcasts_refreshes(stream = model_name.plural)
         
     | 
| 
      
 216 
     | 
    
         
            +
                  after_create_commit  -> { broadcast_refresh_later_to(stream) }
         
     | 
| 
      
 217 
     | 
    
         
            +
                  after_update_commit  -> { broadcast_refresh_later }
         
     | 
| 
      
 218 
     | 
    
         
            +
                  after_destroy_commit -> { broadcast_refresh }
         
     | 
| 
      
 219 
     | 
    
         
            +
                end
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
       115 
221 
     | 
    
         
             
                # All default targets will use the return of this method. Overwrite if you want something else than <tt>model_name.plural</tt>.
         
     | 
| 
       116 
222 
     | 
    
         
             
                def broadcast_target_default
         
     | 
| 
       117 
223 
     | 
    
         
             
                  model_name.plural
         
     | 
| 
       118 
224 
     | 
    
         
             
                end
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                # Executes +block+ preventing both synchronous and asynchronous broadcasts from this model.
         
     | 
| 
      
 227 
     | 
    
         
            +
                def suppressing_turbo_broadcasts(&block)
         
     | 
| 
      
 228 
     | 
    
         
            +
                  original, self.suppressed_turbo_broadcasts = self.suppressed_turbo_broadcasts, true
         
     | 
| 
      
 229 
     | 
    
         
            +
                  yield
         
     | 
| 
      
 230 
     | 
    
         
            +
                ensure
         
     | 
| 
      
 231 
     | 
    
         
            +
                  self.suppressed_turbo_broadcasts = original
         
     | 
| 
      
 232 
     | 
    
         
            +
                end
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
                def suppressed_turbo_broadcasts?
         
     | 
| 
      
 235 
     | 
    
         
            +
                  suppressed_turbo_broadcasts
         
     | 
| 
      
 236 
     | 
    
         
            +
                end
         
     | 
| 
       119 
237 
     | 
    
         
             
              end
         
     | 
| 
       120 
238 
     | 
    
         | 
| 
       121 
239 
     | 
    
         
             
              # Remove this broadcastable model from the dom for subscribers of the stream name identified by the passed streamables.
         
     | 
| 
         @@ -124,7 +242,7 @@ module Turbo::Broadcastable 
     | 
|
| 
       124 
242 
     | 
    
         
             
              #   # Sends <turbo-stream action="remove" target="clearance_5"></turbo-stream> to the stream named "identity:2:clearances"
         
     | 
| 
       125 
243 
     | 
    
         
             
              #   clearance.broadcast_remove_to examiner.identity, :clearances
         
     | 
| 
       126 
244 
     | 
    
         
             
              def broadcast_remove_to(*streamables, target: self)
         
     | 
| 
       127 
     | 
    
         
            -
                Turbo::StreamsChannel.broadcast_remove_to(*streamables, target: target)
         
     | 
| 
      
 245 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_remove_to(*streamables, target: target) unless suppressed_turbo_broadcasts?
         
     | 
| 
       128 
246 
     | 
    
         
             
              end
         
     | 
| 
       129 
247 
     | 
    
         | 
| 
       130 
248 
     | 
    
         
             
              # Same as <tt>#broadcast_remove_to</tt>, but the designated stream is automatically set to the current model.
         
     | 
| 
         @@ -143,7 +261,7 @@ module Turbo::Broadcastable 
     | 
|
| 
       143 
261 
     | 
    
         
             
              #   # to the stream named "identity:2:clearances"
         
     | 
| 
       144 
262 
     | 
    
         
             
              #   clearance.broadcast_replace_to examiner.identity, :clearances, partial: "clearances/other_partial", locals: { a: 1 }
         
     | 
| 
       145 
263 
     | 
    
         
             
              def broadcast_replace_to(*streamables, **rendering)
         
     | 
| 
       146 
     | 
    
         
            -
                Turbo::StreamsChannel.broadcast_replace_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering))
         
     | 
| 
      
 264 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_replace_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
         
     | 
| 
       147 
265 
     | 
    
         
             
              end
         
     | 
| 
       148 
266 
     | 
    
         | 
| 
       149 
267 
     | 
    
         
             
              # Same as <tt>#broadcast_replace_to</tt>, but the designated stream is automatically set to the current model.
         
     | 
| 
         @@ -162,7 +280,7 @@ module Turbo::Broadcastable 
     | 
|
| 
       162 
280 
     | 
    
         
             
              #   # to the stream named "identity:2:clearances"
         
     | 
| 
       163 
281 
     | 
    
         
             
              #   clearance.broadcast_update_to examiner.identity, :clearances, partial: "clearances/other_partial", locals: { a: 1 }
         
     | 
| 
       164 
282 
     | 
    
         
             
              def broadcast_update_to(*streamables, **rendering)
         
     | 
| 
       165 
     | 
    
         
            -
                Turbo::StreamsChannel.broadcast_update_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering))
         
     | 
| 
      
 283 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_update_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
         
     | 
| 
       166 
284 
     | 
    
         
             
              end
         
     | 
| 
       167 
285 
     | 
    
         | 
| 
       168 
286 
     | 
    
         
             
              # Same as <tt>#broadcast_update_to</tt>, but the designated stream is automatically set to the current model.
         
     | 
| 
         @@ -215,7 +333,7 @@ module Turbo::Broadcastable 
     | 
|
| 
       215 
333 
     | 
    
         
             
              #   clearance.broadcast_append_to examiner.identity, :clearances, target: "clearances",
         
     | 
| 
       216 
334 
     | 
    
         
             
              #     partial: "clearances/other_partial", locals: { a: 1 }
         
     | 
| 
       217 
335 
     | 
    
         
             
              def broadcast_append_to(*streamables, target: broadcast_target_default, **rendering)
         
     | 
| 
       218 
     | 
    
         
            -
                Turbo::StreamsChannel.broadcast_append_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
         
     | 
| 
      
 336 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_append_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
         
     | 
| 
       219 
337 
     | 
    
         
             
              end
         
     | 
| 
       220 
338 
     | 
    
         | 
| 
       221 
339 
     | 
    
         
             
              # Same as <tt>#broadcast_append_to</tt>, but the designated stream is automatically set to the current model.
         
     | 
| 
         @@ -236,7 +354,7 @@ module Turbo::Broadcastable 
     | 
|
| 
       236 
354 
     | 
    
         
             
              #   clearance.broadcast_prepend_to examiner.identity, :clearances, target: "clearances",
         
     | 
| 
       237 
355 
     | 
    
         
             
              #     partial: "clearances/other_partial", locals: { a: 1 }
         
     | 
| 
       238 
356 
     | 
    
         
             
              def broadcast_prepend_to(*streamables, target: broadcast_target_default, **rendering)
         
     | 
| 
       239 
     | 
    
         
            -
                Turbo::StreamsChannel.broadcast_prepend_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
         
     | 
| 
      
 357 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_prepend_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
         
     | 
| 
       240 
358 
     | 
    
         
             
              end
         
     | 
| 
       241 
359 
     | 
    
         | 
| 
       242 
360 
     | 
    
         
             
              # Same as <tt>#broadcast_prepend_to</tt>, but the designated stream is automatically set to the current model.
         
     | 
| 
         @@ -244,24 +362,36 @@ module Turbo::Broadcastable 
     | 
|
| 
       244 
362 
     | 
    
         
             
                broadcast_prepend_to self, target: target, **rendering
         
     | 
| 
       245 
363 
     | 
    
         
             
              end
         
     | 
| 
       246 
364 
     | 
    
         | 
| 
      
 365 
     | 
    
         
            +
              #  Broadcast a "page refresh" to the stream name identified by the passed <tt>streamables</tt>. Example:
         
     | 
| 
      
 366 
     | 
    
         
            +
              #
         
     | 
| 
      
 367 
     | 
    
         
            +
              #   # Sends <turbo-stream action="refresh"></turbo-stream> to the stream named "identity:2:clearances"
         
     | 
| 
      
 368 
     | 
    
         
            +
              #   clearance.broadcast_refresh_to examiner.identity, :clearances
         
     | 
| 
      
 369 
     | 
    
         
            +
              def broadcast_refresh_to(*streamables)
         
     | 
| 
      
 370 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_refresh_to(*streamables) unless suppressed_turbo_broadcasts?
         
     | 
| 
      
 371 
     | 
    
         
            +
              end
         
     | 
| 
      
 372 
     | 
    
         
            +
             
     | 
| 
      
 373 
     | 
    
         
            +
              #  Same as <tt>#broadcast_refresh_to</tt>, but the designated stream is automatically set to the current model.
         
     | 
| 
      
 374 
     | 
    
         
            +
              def broadcast_refresh
         
     | 
| 
      
 375 
     | 
    
         
            +
                broadcast_refresh_to self
         
     | 
| 
      
 376 
     | 
    
         
            +
              end
         
     | 
| 
      
 377 
     | 
    
         
            +
             
     | 
| 
       247 
378 
     | 
    
         
             
              # Broadcast a named <tt>action</tt>, allowing for dynamic dispatch, instead of using the concrete action methods. Examples:
         
     | 
| 
       248 
379 
     | 
    
         
             
              #
         
     | 
| 
       249 
380 
     | 
    
         
             
              #   # Sends <turbo-stream action="prepend" target="clearances"><template><div id="clearance_5">My Clearance</div></template></turbo-stream>
         
     | 
| 
       250 
381 
     | 
    
         
             
              #   # to the stream named "identity:2:clearances"
         
     | 
| 
       251 
382 
     | 
    
         
             
              #   clearance.broadcast_action_to examiner.identity, :clearances, action: :prepend, target: "clearances"
         
     | 
| 
       252 
     | 
    
         
            -
              def broadcast_action_to(*streamables, action:, target: broadcast_target_default, **rendering)
         
     | 
| 
       253 
     | 
    
         
            -
                Turbo::StreamsChannel.broadcast_action_to(*streamables, action: action, target: target, **broadcast_rendering_with_defaults(rendering))
         
     | 
| 
      
 383 
     | 
    
         
            +
              def broadcast_action_to(*streamables, action:, target: broadcast_target_default, attributes: {}, **rendering)
         
     | 
| 
      
 384 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_action_to(*streamables, action: action, target: target, attributes: attributes, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
         
     | 
| 
       254 
385 
     | 
    
         
             
              end
         
     | 
| 
       255 
386 
     | 
    
         | 
| 
       256 
387 
     | 
    
         
             
              # Same as <tt>#broadcast_action_to</tt>, but the designated stream is automatically set to the current model.
         
     | 
| 
       257 
     | 
    
         
            -
              def broadcast_action(action, target: broadcast_target_default, **rendering)
         
     | 
| 
       258 
     | 
    
         
            -
                broadcast_action_to self, action: action, target: target, **rendering
         
     | 
| 
      
 388 
     | 
    
         
            +
              def broadcast_action(action, target: broadcast_target_default, attributes: {}, **rendering)
         
     | 
| 
      
 389 
     | 
    
         
            +
                broadcast_action_to self, action: action, target: target, attributes: attributes, **rendering
         
     | 
| 
       259 
390 
     | 
    
         
             
              end
         
     | 
| 
       260 
391 
     | 
    
         | 
| 
       261 
     | 
    
         
            -
             
     | 
| 
       262 
392 
     | 
    
         
             
              # Same as <tt>broadcast_replace_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
         
     | 
| 
       263 
393 
     | 
    
         
             
              def broadcast_replace_later_to(*streamables, **rendering)
         
     | 
| 
       264 
     | 
    
         
            -
                Turbo::StreamsChannel.broadcast_replace_later_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering))
         
     | 
| 
      
 394 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_replace_later_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
         
     | 
| 
       265 
395 
     | 
    
         
             
              end
         
     | 
| 
       266 
396 
     | 
    
         | 
| 
       267 
397 
     | 
    
         
             
              # Same as <tt>#broadcast_replace_later_to</tt>, but the designated stream is automatically set to the current model.
         
     | 
| 
         @@ -271,7 +401,7 @@ module Turbo::Broadcastable 
     | 
|
| 
       271 
401 
     | 
    
         | 
| 
       272 
402 
     | 
    
         
             
              # Same as <tt>broadcast_update_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
         
     | 
| 
       273 
403 
     | 
    
         
             
              def broadcast_update_later_to(*streamables, **rendering)
         
     | 
| 
       274 
     | 
    
         
            -
                Turbo::StreamsChannel.broadcast_update_later_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering))
         
     | 
| 
      
 404 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_update_later_to(*streamables, target: self, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
         
     | 
| 
       275 
405 
     | 
    
         
             
              end
         
     | 
| 
       276 
406 
     | 
    
         | 
| 
       277 
407 
     | 
    
         
             
              # Same as <tt>#broadcast_update_later_to</tt>, but the designated stream is automatically set to the current model.
         
     | 
| 
         @@ -281,7 +411,7 @@ module Turbo::Broadcastable 
     | 
|
| 
       281 
411 
     | 
    
         | 
| 
       282 
412 
     | 
    
         
             
              # Same as <tt>broadcast_append_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
         
     | 
| 
       283 
413 
     | 
    
         
             
              def broadcast_append_later_to(*streamables, target: broadcast_target_default, **rendering)
         
     | 
| 
       284 
     | 
    
         
            -
                Turbo::StreamsChannel.broadcast_append_later_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
         
     | 
| 
      
 414 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_append_later_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
         
     | 
| 
       285 
415 
     | 
    
         
             
              end
         
     | 
| 
       286 
416 
     | 
    
         | 
| 
       287 
417 
     | 
    
         
             
              # Same as <tt>#broadcast_append_later_to</tt>, but the designated stream is automatically set to the current model.
         
     | 
| 
         @@ -291,7 +421,7 @@ module Turbo::Broadcastable 
     | 
|
| 
       291 
421 
     | 
    
         | 
| 
       292 
422 
     | 
    
         
             
              # Same as <tt>broadcast_prepend_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
         
     | 
| 
       293 
423 
     | 
    
         
             
              def broadcast_prepend_later_to(*streamables, target: broadcast_target_default, **rendering)
         
     | 
| 
       294 
     | 
    
         
            -
                Turbo::StreamsChannel.broadcast_prepend_later_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering))
         
     | 
| 
      
 424 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_prepend_later_to(*streamables, target: target, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
         
     | 
| 
       295 
425 
     | 
    
         
             
              end
         
     | 
| 
       296 
426 
     | 
    
         | 
| 
       297 
427 
     | 
    
         
             
              # Same as <tt>#broadcast_prepend_later_to</tt>, but the designated stream is automatically set to the current model.
         
     | 
| 
         @@ -299,14 +429,24 @@ module Turbo::Broadcastable 
     | 
|
| 
       299 
429 
     | 
    
         
             
                broadcast_prepend_later_to self, target: target, **rendering
         
     | 
| 
       300 
430 
     | 
    
         
             
              end
         
     | 
| 
       301 
431 
     | 
    
         | 
| 
      
 432 
     | 
    
         
            +
              #  Same as <tt>broadcast_refresh_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
         
     | 
| 
      
 433 
     | 
    
         
            +
              def broadcast_refresh_later_to(*streamables)
         
     | 
| 
      
 434 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_refresh_later_to(*streamables, request_id: Turbo.current_request_id) unless suppressed_turbo_broadcasts?
         
     | 
| 
      
 435 
     | 
    
         
            +
              end
         
     | 
| 
      
 436 
     | 
    
         
            +
             
     | 
| 
      
 437 
     | 
    
         
            +
              #  Same as <tt>#broadcast_refresh_later_to</tt>, but the designated stream is automatically set to the current model.
         
     | 
| 
      
 438 
     | 
    
         
            +
              def broadcast_refresh_later
         
     | 
| 
      
 439 
     | 
    
         
            +
                broadcast_refresh_later_to self
         
     | 
| 
      
 440 
     | 
    
         
            +
              end
         
     | 
| 
      
 441 
     | 
    
         
            +
             
     | 
| 
       302 
442 
     | 
    
         
             
              # Same as <tt>broadcast_action_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
         
     | 
| 
       303 
     | 
    
         
            -
              def broadcast_action_later_to(*streamables, action:, target: broadcast_target_default, **rendering)
         
     | 
| 
       304 
     | 
    
         
            -
                Turbo::StreamsChannel.broadcast_action_later_to(*streamables, action: action, target: target, **broadcast_rendering_with_defaults(rendering))
         
     | 
| 
      
 443 
     | 
    
         
            +
              def broadcast_action_later_to(*streamables, action:, target: broadcast_target_default, attributes: {}, **rendering)
         
     | 
| 
      
 444 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_action_later_to(*streamables, action: action, target: target, attributes: attributes, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
         
     | 
| 
       305 
445 
     | 
    
         
             
              end
         
     | 
| 
       306 
446 
     | 
    
         | 
| 
       307 
447 
     | 
    
         
             
              # Same as <tt>#broadcast_action_later_to</tt>, but the designated stream is automatically set to the current model.
         
     | 
| 
       308 
     | 
    
         
            -
              def broadcast_action_later(action:, target: broadcast_target_default, **rendering)
         
     | 
| 
       309 
     | 
    
         
            -
                broadcast_action_later_to self, action: action, target: target, **rendering
         
     | 
| 
      
 448 
     | 
    
         
            +
              def broadcast_action_later(action:, target: broadcast_target_default, attributes: {}, **rendering)
         
     | 
| 
      
 449 
     | 
    
         
            +
                broadcast_action_later_to self, action: action, target: target, attributes: attributes, **rendering
         
     | 
| 
       310 
450 
     | 
    
         
             
              end
         
     | 
| 
       311 
451 
     | 
    
         | 
| 
       312 
452 
     | 
    
         
             
              # Render a turbo stream template with this broadcastable model passed as the local variable. Example:
         
     | 
| 
         @@ -325,7 +465,7 @@ module Turbo::Broadcastable 
     | 
|
| 
       325 
465 
     | 
    
         
             
              #
         
     | 
| 
       326 
466 
     | 
    
         
             
              # Note that rendering inline via this method will cause template rendering to happen synchronously. That is usually not
         
     | 
| 
       327 
467 
     | 
    
         
             
              # desireable for model callbacks, certainly not if those callbacks are inside of a transaction. Most of the time you should
         
     | 
| 
       328 
     | 
    
         
            -
              # be using  
     | 
| 
      
 468 
     | 
    
         
            +
              # be using +broadcast_render_later+, unless you specifically know why synchronous rendering is needed.
         
     | 
| 
       329 
469 
     | 
    
         
             
              def broadcast_render(**rendering)
         
     | 
| 
       330 
470 
     | 
    
         
             
                broadcast_render_to self, **rendering
         
     | 
| 
       331 
471 
     | 
    
         
             
              end
         
     | 
| 
         @@ -335,12 +475,12 @@ module Turbo::Broadcastable 
     | 
|
| 
       335 
475 
     | 
    
         
             
              #
         
     | 
| 
       336 
476 
     | 
    
         
             
              # Note that rendering inline via this method will cause template rendering to happen synchronously. That is usually not
         
     | 
| 
       337 
477 
     | 
    
         
             
              # desireable for model callbacks, certainly not if those callbacks are inside of a transaction. Most of the time you should
         
     | 
| 
       338 
     | 
    
         
            -
              # be using  
     | 
| 
      
 478 
     | 
    
         
            +
              # be using +broadcast_render_later_to+, unless you specifically know why synchronous rendering is needed.
         
     | 
| 
       339 
479 
     | 
    
         
             
              def broadcast_render_to(*streamables, **rendering)
         
     | 
| 
       340 
     | 
    
         
            -
                Turbo::StreamsChannel.broadcast_render_to(*streamables, **broadcast_rendering_with_defaults(rendering))
         
     | 
| 
      
 480 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_render_to(*streamables, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
         
     | 
| 
       341 
481 
     | 
    
         
             
              end
         
     | 
| 
       342 
482 
     | 
    
         | 
| 
       343 
     | 
    
         
            -
              # Same as <tt> 
     | 
| 
      
 483 
     | 
    
         
            +
              # Same as <tt>broadcast_render_to</tt> but run asynchronously via a <tt>Turbo::Streams::BroadcastJob</tt>.
         
     | 
| 
       344 
484 
     | 
    
         
             
              def broadcast_render_later(**rendering)
         
     | 
| 
       345 
485 
     | 
    
         
             
                broadcast_render_later_to self, **rendering
         
     | 
| 
       346 
486 
     | 
    
         
             
              end
         
     | 
| 
         @@ -348,10 +488,9 @@ module Turbo::Broadcastable 
     | 
|
| 
       348 
488 
     | 
    
         
             
              # Same as <tt>broadcast_render_later</tt> but run with the added option of naming the stream using the passed
         
     | 
| 
       349 
489 
     | 
    
         
             
              # <tt>streamables</tt>.
         
     | 
| 
       350 
490 
     | 
    
         
             
              def broadcast_render_later_to(*streamables, **rendering)
         
     | 
| 
       351 
     | 
    
         
            -
                Turbo::StreamsChannel.broadcast_render_later_to(*streamables, **broadcast_rendering_with_defaults(rendering))
         
     | 
| 
      
 491 
     | 
    
         
            +
                Turbo::StreamsChannel.broadcast_render_later_to(*streamables, **broadcast_rendering_with_defaults(rendering)) unless suppressed_turbo_broadcasts?
         
     | 
| 
       352 
492 
     | 
    
         
             
              end
         
     | 
| 
       353 
493 
     | 
    
         | 
| 
       354 
     | 
    
         
            -
             
     | 
| 
       355 
494 
     | 
    
         
             
              private
         
     | 
| 
       356 
495 
     | 
    
         
             
                def broadcast_target_default
         
     | 
| 
       357 
496 
     | 
    
         
             
                  self.class.broadcast_target_default
         
     | 
| 
         @@ -361,12 +500,14 @@ module Turbo::Broadcastable 
     | 
|
| 
       361 
500 
     | 
    
         
             
                  options.tap do |o|
         
     | 
| 
       362 
501 
     | 
    
         
             
                    # Add the current instance into the locals with the element name (which is the un-namespaced name)
         
     | 
| 
       363 
502 
     | 
    
         
             
                    # as the key. This parallels how the ActionView::ObjectRenderer would create a local variable.
         
     | 
| 
       364 
     | 
    
         
            -
                    o[:locals] = (o[:locals] || {}).reverse_merge!(model_name.element.to_sym => self)
         
     | 
| 
      
 503 
     | 
    
         
            +
                    o[:locals] = (o[:locals] || {}).reverse_merge!(model_name.element.to_sym => self, request_id: Turbo.current_request_id).compact
         
     | 
| 
       365 
504 
     | 
    
         | 
| 
       366 
505 
     | 
    
         
             
                    if o[:html] || o[:partial]
         
     | 
| 
       367 
506 
     | 
    
         
             
                      return o
         
     | 
| 
       368 
507 
     | 
    
         
             
                    elsif o[:template] || o[:renderable]
         
     | 
| 
       369 
508 
     | 
    
         
             
                      o[:layout] = false
         
     | 
| 
      
 509 
     | 
    
         
            +
                    elsif o[:render] == false
         
     | 
| 
      
 510 
     | 
    
         
            +
                      return o
         
     | 
| 
       370 
511 
     | 
    
         
             
                    else
         
     | 
| 
       371 
512 
     | 
    
         
             
                      # if none of these options are passed in, it will set a partial from #to_partial_path
         
     | 
| 
       372 
513 
     | 
    
         
             
                      o[:partial] ||= to_partial_path
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class Turbo::Debouncer
         
     | 
| 
      
 2 
     | 
    
         
            +
              attr_reader :delay, :scheduled_task
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
              DEFAULT_DELAY = 0.5
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def initialize(delay: DEFAULT_DELAY)
         
     | 
| 
      
 7 
     | 
    
         
            +
                @delay = delay
         
     | 
| 
      
 8 
     | 
    
         
            +
                @scheduled_task = nil
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              def debounce(&block)
         
     | 
| 
      
 12 
     | 
    
         
            +
                scheduled_task&.cancel unless scheduled_task&.complete?
         
     | 
| 
      
 13 
     | 
    
         
            +
                @scheduled_task = Concurrent::ScheduledTask.execute(delay, &block)
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              def wait
         
     | 
| 
      
 17 
     | 
    
         
            +
                scheduled_task&.wait(wait_timeout)
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
              private
         
     | 
| 
      
 21 
     | 
    
         
            +
                def wait_timeout
         
     | 
| 
      
 22 
     | 
    
         
            +
                  delay + 1
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -22,6 +22,24 @@ 
     | 
|
| 
       22 
22 
     | 
    
         
             
            #   <%= turbo_stream.append dom_id(topic_merge) do %>
         
     | 
| 
       23 
23 
     | 
    
         
             
            #     <%= link_to topic_merge.topic.name, topic_path(topic_merge.topic) %>
         
     | 
| 
       24 
24 
     | 
    
         
             
            #   <% end %>
         
     | 
| 
      
 25 
     | 
    
         
            +
            #
         
     | 
| 
      
 26 
     | 
    
         
            +
            # To integrate with custom actions, extend this class in response to the :turbo_streams_tag_builder load hook:
         
     | 
| 
      
 27 
     | 
    
         
            +
            #
         
     | 
| 
      
 28 
     | 
    
         
            +
            #   ActiveSupport.on_load :turbo_streams_tag_builder do
         
     | 
| 
      
 29 
     | 
    
         
            +
            #     def highlight(target)
         
     | 
| 
      
 30 
     | 
    
         
            +
            #       action :highlight, target
         
     | 
| 
      
 31 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 32 
     | 
    
         
            +
            #
         
     | 
| 
      
 33 
     | 
    
         
            +
            #     def highlight_all(targets)
         
     | 
| 
      
 34 
     | 
    
         
            +
            #       action_all :highlight, targets
         
     | 
| 
      
 35 
     | 
    
         
            +
            #     end
         
     | 
| 
      
 36 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 37 
     | 
    
         
            +
            #
         
     | 
| 
      
 38 
     | 
    
         
            +
            #   turbo_stream.highlight "my-element"
         
     | 
| 
      
 39 
     | 
    
         
            +
            #   # => <turbo-stream action="highlight" target="my-element"><template></template></turbo-stream>
         
     | 
| 
      
 40 
     | 
    
         
            +
            #
         
     | 
| 
      
 41 
     | 
    
         
            +
            #   turbo_stream.highlight_all ".my-selector"
         
     | 
| 
      
 42 
     | 
    
         
            +
            #   # => <turbo-stream action="highlight" targets=".my-selector"><template></template></turbo-stream>
         
     | 
| 
       25 
43 
     | 
    
         
             
            class Turbo::Streams::TagBuilder
         
     | 
| 
       26 
44 
     | 
    
         
             
              include Turbo::Streams::ActionHelper
         
     | 
| 
       27 
45 
     | 
    
         | 
| 
         @@ -246,4 +264,6 @@ class Turbo::Streams::TagBuilder 
     | 
|
| 
       246 
264 
     | 
    
         
             
                    @view_context.render(partial: record, formats: :html)
         
     | 
| 
       247 
265 
     | 
    
         
             
                  end
         
     | 
| 
       248 
266 
     | 
    
         
             
                end
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
              ActiveSupport.run_load_hooks :turbo_streams_tag_builder, self
         
     | 
| 
       249 
269 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # A decorated debouncer that will store instances in the current thread clearing them
         
     | 
| 
      
 2 
     | 
    
         
            +
            # after the debounced logic triggers.
         
     | 
| 
      
 3 
     | 
    
         
            +
            class Turbo::ThreadDebouncer
         
     | 
| 
      
 4 
     | 
    
         
            +
              delegate :wait, to: :debouncer
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def self.for(key, delay: Turbo::Debouncer::DEFAULT_DELAY)
         
     | 
| 
      
 7 
     | 
    
         
            +
                Thread.current[key] ||= new(key, Thread.current, delay: delay)
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              private_class_method :new
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
              def initialize(key, thread, delay: )
         
     | 
| 
      
 13 
     | 
    
         
            +
                @key = key
         
     | 
| 
      
 14 
     | 
    
         
            +
                @debouncer = Turbo::Debouncer.new(delay: delay)
         
     | 
| 
      
 15 
     | 
    
         
            +
                @thread = thread
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              def debounce
         
     | 
| 
      
 19 
     | 
    
         
            +
                debouncer.debounce do
         
     | 
| 
      
 20 
     | 
    
         
            +
                  yield.tap do
         
     | 
| 
      
 21 
     | 
    
         
            +
                    thread[key] = nil
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
              private
         
     | 
| 
      
 27 
     | 
    
         
            +
                attr_reader :key, :debouncer, :thread
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
    
        data/config/routes.rb
    CHANGED
    
    | 
         @@ -1,4 +1,3 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # FIXME: Offer flag to opt out of these native routes
         
     | 
| 
       2 
1 
     | 
    
         
             
            Rails.application.routes.draw do
         
     | 
| 
       3 
2 
     | 
    
         
             
              get "recede_historical_location"  => "turbo/native/navigation#recede",  as: :turbo_recede_historical_location
         
     | 
| 
       4 
3 
     | 
    
         
             
              get "resume_historical_location"  => "turbo/native/navigation#resume",  as: :turbo_resume_historical_location
         
     | 
| 
         @@ -2,4 +2,4 @@ say "Import Turbo" 
     | 
|
| 
       2 
2 
     | 
    
         
             
            append_to_file "app/javascript/application.js", %(import "@hotwired/turbo-rails"\n)
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
4 
     | 
    
         
             
            say "Pin Turbo"
         
     | 
| 
       5 
     | 
    
         
            -
            append_to_file "config/importmap.rb", %(pin "@hotwired/turbo-rails", to: "turbo.min.js" 
     | 
| 
      
 5 
     | 
    
         
            +
            append_to_file "config/importmap.rb", %(pin "@hotwired/turbo-rails", to: "turbo.min.js"\n)
         
     | 
| 
         @@ -11,14 +11,14 @@ module Turbo 
     | 
|
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                  # Asserts that `<turbo-stream>` elements were broadcast over Action Cable
         
     | 
| 
       13 
13 
     | 
    
         
             
                  #
         
     | 
| 
       14 
     | 
    
         
            -
                  #  
     | 
| 
      
 14 
     | 
    
         
            +
                  # ==== Arguments
         
     | 
| 
       15 
15 
     | 
    
         
             
                  #
         
     | 
| 
       16 
16 
     | 
    
         
             
                  # * <tt>stream_name_or_object</tt> the objects used to generate the
         
     | 
| 
       17 
17 
     | 
    
         
             
                  #   channel Action Cable name, or the name itself
         
     | 
| 
       18 
18 
     | 
    
         
             
                  # * <tt>&block</tt> optional block executed before the
         
     | 
| 
       19 
19 
     | 
    
         
             
                  #   assertion
         
     | 
| 
       20 
20 
     | 
    
         
             
                  #
         
     | 
| 
       21 
     | 
    
         
            -
                  #  
     | 
| 
      
 21 
     | 
    
         
            +
                  # ==== Options
         
     | 
| 
       22 
22 
     | 
    
         
             
                  #
         
     | 
| 
       23 
23 
     | 
    
         
             
                  # * <tt>count:</tt> the number of `<turbo-stream>` elements that are
         
     | 
| 
       24 
24 
     | 
    
         
             
                  # expected to be broadcast
         
     | 
| 
         @@ -64,13 +64,13 @@ module Turbo 
     | 
|
| 
       64 
64 
     | 
    
         
             
                    else
         
     | 
| 
       65 
65 
     | 
    
         
             
                      broadcasts = "Turbo Stream broadcast".pluralize(count)
         
     | 
| 
       66 
66 
     | 
    
         | 
| 
       67 
     | 
    
         
            -
                      assert count == payloads.count, "Expected #{count} #{broadcasts} on #{stream_name.inspect}, but there were  
     | 
| 
      
 67 
     | 
    
         
            +
                      assert count == payloads.count, "Expected #{count} #{broadcasts} on #{stream_name.inspect}, but there were #{payloads.count}"
         
     | 
| 
       68 
68 
     | 
    
         
             
                    end
         
     | 
| 
       69 
69 
     | 
    
         
             
                  end
         
     | 
| 
       70 
70 
     | 
    
         | 
| 
       71 
71 
     | 
    
         
             
                  # Asserts that no `<turbo-stream>` elements were broadcast over Action Cable
         
     | 
| 
       72 
72 
     | 
    
         
             
                  #
         
     | 
| 
       73 
     | 
    
         
            -
                  #  
     | 
| 
      
 73 
     | 
    
         
            +
                  # ==== Arguments
         
     | 
| 
       74 
74 
     | 
    
         
             
                  #
         
     | 
| 
       75 
75 
     | 
    
         
             
                  # * <tt>stream_name_or_object</tt> the objects used to generate the
         
     | 
| 
       76 
76 
     | 
    
         
             
                  #   channel Action Cable name, or the name itself
         
     | 
| 
         @@ -113,7 +113,7 @@ module Turbo 
     | 
|
| 
       113 
113 
     | 
    
         | 
| 
       114 
114 
     | 
    
         
             
                  # Captures any `<turbo-stream>` elements that were broadcast over Action Cable
         
     | 
| 
       115 
115 
     | 
    
         
             
                  #
         
     | 
| 
       116 
     | 
    
         
            -
                  #  
     | 
| 
      
 116 
     | 
    
         
            +
                  # ==== Arguments
         
     | 
| 
       117 
117 
     | 
    
         
             
                  #
         
     | 
| 
       118 
118 
     | 
    
         
             
                  # * <tt>stream_name_or_object</tt> the objects used to generate the
         
     | 
| 
       119 
119 
     | 
    
         
             
                  #   channel Action Cable name, or the name itself
         
     | 
    
        data/lib/turbo/engine.rb
    CHANGED
    
    | 
         @@ -46,6 +46,12 @@ module Turbo 
     | 
|
| 
       46 
46 
     | 
    
         
             
                  end
         
     | 
| 
       47 
47 
     | 
    
         
             
                end
         
     | 
| 
       48 
48 
     | 
    
         | 
| 
      
 49 
     | 
    
         
            +
                initializer "turbo.request_id_tracking" do
         
     | 
| 
      
 50 
     | 
    
         
            +
                  ActiveSupport.on_load(:action_controller) do
         
     | 
| 
      
 51 
     | 
    
         
            +
                    include Turbo::RequestIdTracking
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
       49 
55 
     | 
    
         
             
                initializer "turbo.broadcastable" do
         
     | 
| 
       50 
56 
     | 
    
         
             
                  ActiveSupport.on_load(:active_record) do
         
     | 
| 
       51 
57 
     | 
    
         
             
                    include Turbo::Broadcastable
         
     | 
| 
         @@ -75,11 +81,16 @@ module Turbo 
     | 
|
| 
       75 
81 
     | 
    
         
             
                initializer "turbo.test_assertions" do
         
     | 
| 
       76 
82 
     | 
    
         
             
                  ActiveSupport.on_load(:active_support_test_case) do
         
     | 
| 
       77 
83 
     | 
    
         
             
                    require "turbo/test_assertions"
         
     | 
| 
       78 
     | 
    
         
            -
                    require "turbo/broadcastable/test_helper"
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
84 
     | 
    
         
             
                    include Turbo::TestAssertions
         
     | 
| 
       81 
85 
     | 
    
         
             
                  end
         
     | 
| 
       82 
86 
     | 
    
         | 
| 
      
 87 
     | 
    
         
            +
                  ActiveSupport.on_load(:action_cable) do
         
     | 
| 
      
 88 
     | 
    
         
            +
                    ActiveSupport.on_load(:active_support_test_case) do
         
     | 
| 
      
 89 
     | 
    
         
            +
                      require "turbo/broadcastable/test_helper"
         
     | 
| 
      
 90 
     | 
    
         
            +
                      include Turbo::Broadcastable::TestHelper
         
     | 
| 
      
 91 
     | 
    
         
            +
                    end
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
       83 
94 
     | 
    
         
             
                  ActiveSupport.on_load(:action_dispatch_integration_test) do
         
     | 
| 
       84 
95 
     | 
    
         
             
                    require "turbo/test_assertions/integration_test_assertions"
         
     | 
| 
       85 
96 
     | 
    
         | 
| 
         @@ -4,7 +4,7 @@ module Turbo 
     | 
|
| 
       4 
4 
     | 
    
         
             
                  # Assert that the Turbo Stream request's response body's HTML contains a
         
     | 
| 
       5 
5 
     | 
    
         
             
                  # `<turbo-stream>` element.
         
     | 
| 
       6 
6 
     | 
    
         
             
                  #
         
     | 
| 
       7 
     | 
    
         
            -
                  #  
     | 
| 
      
 7 
     | 
    
         
            +
                  # ==== Options
         
     | 
| 
       8 
8 
     | 
    
         
             
                  #
         
     | 
| 
       9 
9 
     | 
    
         
             
                  # * <tt>:status</tt> [Integer, Symbol] the HTTP response status
         
     | 
| 
       10 
10 
     | 
    
         
             
                  # * <tt>:action</tt> [String] matches the element's <tt>[action]</tt>
         
     | 
| 
         @@ -47,7 +47,7 @@ module Turbo 
     | 
|
| 
       47 
47 
     | 
    
         
             
                  # Assert that the Turbo Stream request's response body's HTML does not
         
     | 
| 
       48 
48 
     | 
    
         
             
                  # contain a `<turbo-stream>` element.
         
     | 
| 
       49 
49 
     | 
    
         
             
                  #
         
     | 
| 
       50 
     | 
    
         
            -
                  #  
     | 
| 
      
 50 
     | 
    
         
            +
                  # ==== Options
         
     | 
| 
       51 
51 
     | 
    
         
             
                  #
         
     | 
| 
       52 
52 
     | 
    
         
             
                  # * <tt>:status</tt> [Integer, Symbol] the HTTP response status
         
     | 
| 
       53 
53 
     | 
    
         
             
                  # * <tt>:action</tt> [String] matches the element's <tt>[action]</tt>
         
     | 
| 
         @@ -10,7 +10,7 @@ module Turbo 
     | 
|
| 
       10 
10 
     | 
    
         
             
                # Assert that the rendered fragment of HTML contains a `<turbo-stream>`
         
     | 
| 
       11 
11 
     | 
    
         
             
                # element.
         
     | 
| 
       12 
12 
     | 
    
         
             
                #
         
     | 
| 
       13 
     | 
    
         
            -
                #  
     | 
| 
      
 13 
     | 
    
         
            +
                # ==== Options
         
     | 
| 
       14 
14 
     | 
    
         
             
                #
         
     | 
| 
       15 
15 
     | 
    
         
             
                # * <tt>:action</tt> [String] matches the element's <tt>[action]</tt>
         
     | 
| 
       16 
16 
     | 
    
         
             
                #   attribute
         
     | 
| 
         @@ -55,7 +55,7 @@ module Turbo 
     | 
|
| 
       55 
55 
     | 
    
         
             
                # Assert that the rendered fragment of HTML does not contain a `<turbo-stream>`
         
     | 
| 
       56 
56 
     | 
    
         
             
                # element.
         
     | 
| 
       57 
57 
     | 
    
         
             
                #
         
     | 
| 
       58 
     | 
    
         
            -
                #  
     | 
| 
      
 58 
     | 
    
         
            +
                # ==== Options
         
     | 
| 
       59 
59 
     | 
    
         
             
                #
         
     | 
| 
       60 
60 
     | 
    
         
             
                # * <tt>:action</tt> [String] matches the element's <tt>[action]</tt>
         
     | 
| 
       61 
61 
     | 
    
         
             
                #   attribute
         
     | 
    
        data/lib/turbo/version.rb
    CHANGED
    
    
    
        data/lib/turbo-rails.rb
    CHANGED
    
    | 
         @@ -1,10 +1,13 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require "turbo/engine"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "active_support/core_ext/module/attribute_accessors_per_thread"
         
     | 
| 
       2 
3 
     | 
    
         | 
| 
       3 
4 
     | 
    
         
             
            module Turbo
         
     | 
| 
       4 
5 
     | 
    
         
             
              extend ActiveSupport::Autoload
         
     | 
| 
       5 
6 
     | 
    
         | 
| 
       6 
7 
     | 
    
         
             
              mattr_accessor :draw_routes, default: true
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
      
 9 
     | 
    
         
            +
              thread_mattr_accessor :current_request_id
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
       8 
11 
     | 
    
         
             
              class << self
         
     | 
| 
       9 
12 
     | 
    
         
             
                attr_writer :signed_stream_verifier_key
         
     | 
| 
       10 
13 
     | 
    
         | 
| 
         @@ -15,5 +18,12 @@ module Turbo 
     | 
|
| 
       15 
18 
     | 
    
         
             
                def signed_stream_verifier_key
         
     | 
| 
       16 
19 
     | 
    
         
             
                  @signed_stream_verifier_key or raise ArgumentError, "Turbo requires a signed_stream_verifier_key"
         
     | 
| 
       17 
20 
     | 
    
         
             
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                def with_request_id(request_id)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  old_request_id, self.current_request_id = self.current_request_id, request_id
         
     | 
| 
      
 24 
     | 
    
         
            +
                  yield
         
     | 
| 
      
 25 
     | 
    
         
            +
                ensure
         
     | 
| 
      
 26 
     | 
    
         
            +
                  self.current_request_id = old_request_id
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
       18 
28 
     | 
    
         
             
              end
         
     | 
| 
       19 
29 
     | 
    
         
             
            end
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: turbo-rails
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version:  
     | 
| 
      
 4 
     | 
    
         
            +
              version: 2.0.4
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Sam Stephenson
         
     | 
| 
         @@ -10,7 +10,7 @@ authors: 
     | 
|
| 
       10 
10 
     | 
    
         
             
            autorequire:
         
     | 
| 
       11 
11 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       12 
12 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       13 
     | 
    
         
            -
            date:  
     | 
| 
      
 13 
     | 
    
         
            +
            date: 2024-02-21 00:00:00.000000000 Z
         
     | 
| 
       14 
14 
     | 
    
         
             
            dependencies:
         
     | 
| 
       15 
15 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       16 
16 
     | 
    
         
             
              name: activejob
         
     | 
| 
         @@ -69,6 +69,7 @@ files: 
     | 
|
| 
       69 
69 
     | 
    
         
             
            - app/channels/turbo/streams/broadcasts.rb
         
     | 
| 
       70 
70 
     | 
    
         
             
            - app/channels/turbo/streams/stream_name.rb
         
     | 
| 
       71 
71 
     | 
    
         
             
            - app/channels/turbo/streams_channel.rb
         
     | 
| 
      
 72 
     | 
    
         
            +
            - app/controllers/concerns/turbo/request_id_tracking.rb
         
     | 
| 
       72 
73 
     | 
    
         
             
            - app/controllers/turbo/frames/frame_request.rb
         
     | 
| 
       73 
74 
     | 
    
         
             
            - app/controllers/turbo/native/navigation.rb
         
     | 
| 
       74 
75 
     | 
    
         
             
            - app/controllers/turbo/native/navigation_controller.rb
         
     | 
| 
         @@ -85,8 +86,11 @@ files: 
     | 
|
| 
       85 
86 
     | 
    
         
             
            - app/javascript/turbo/snakeize.js
         
     | 
| 
       86 
87 
     | 
    
         
             
            - app/jobs/turbo/streams/action_broadcast_job.rb
         
     | 
| 
       87 
88 
     | 
    
         
             
            - app/jobs/turbo/streams/broadcast_job.rb
         
     | 
| 
      
 89 
     | 
    
         
            +
            - app/jobs/turbo/streams/broadcast_stream_job.rb
         
     | 
| 
       88 
90 
     | 
    
         
             
            - app/models/concerns/turbo/broadcastable.rb
         
     | 
| 
      
 91 
     | 
    
         
            +
            - app/models/turbo/debouncer.rb
         
     | 
| 
       89 
92 
     | 
    
         
             
            - app/models/turbo/streams/tag_builder.rb
         
     | 
| 
      
 93 
     | 
    
         
            +
            - app/models/turbo/thread_debouncer.rb
         
     | 
| 
       90 
94 
     | 
    
         
             
            - app/views/layouts/turbo_rails/frame.html.erb
         
     | 
| 
       91 
95 
     | 
    
         
             
            - config/routes.rb
         
     | 
| 
       92 
96 
     | 
    
         
             
            - lib/install/turbo_needs_redis.rb
         
     |