Module: TurboOverlay::Controller
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/turbo_overlay/controller.rb
Overview
Controller concern. Include in ‘ApplicationController` (or any controller you want overlay-aware):
class ApplicationController < ActionController::Base
include TurboOverlay::Controller
end
The concern auto-installs a ‘layout` proc that swaps in the matching overlay layout for overlay requests and preserves `“turbo_rails/frame”` for plain turbo-frame requests (so including this concern does not regress Turbo’s frame-layout optimization). For apps with a custom layout method, call ‘turbo_overlay_layout` from your method — see the README “A note on custom layouts” section.
Constant Summary collapse
- OVERLAY_FRAME_PREFIX =
"turbo_overlay_".freeze
- OVERLAY_TYPE_HEADER =
"X-Turbo-Overlay".freeze
- OVERLAY_ID_HEADER =
"X-Turbo-Overlay-Id".freeze
- OVERLAY_POSITION_HEADER =
"X-Turbo-Overlay-Position".freeze
- OVERLAY_ALIGN_HEADER =
"X-Turbo-Overlay-Align".freeze
- OVERLAY_OFFSET_HEADER =
"X-Turbo-Overlay-Offset".freeze
- OVERLAY_BACKDROP_HEADER =
"X-Turbo-Overlay-Backdrop".freeze
- OVERLAY_CLOSE_HEADER =
"X-Turbo-Overlay-Close".freeze
- OVERLAY_KEEP_OPEN_HEADER =
"X-Turbo-Overlay-Keep-Open".freeze
- ALLOWED_POSITIONS =
Whitelists for values that originate from request headers and get reflected into rendered chrome (CSS class tokens, DOM ids, frame names). Constraining them at the resolver protects every downstream consumer — gem partials, generator templates, JS data attributes — without each having to re-validate.
%i[left right top bottom].freeze
- ALLOWED_ALIGNS =
%i[start center end].freeze
- OVERLAY_ID_FORMAT =
/\A[A-Za-z0-9_-]{1,64}\z/.freeze
- OFFSET_RANGE =
(-10_000..10_000).freeze
Instance Method Summary collapse
-
#drawer_request? ⇒ Boolean
—– drawer —–.
-
#hint_request? ⇒ Boolean
—– hint —–.
-
#modal_request? ⇒ Boolean
—– modal —–.
-
#overlay_hintable_request? ⇒ Boolean
True if the current request will use the hint template — either a hover prefetch (which the gem’s JS extracts the template from) or an explicit ‘:hint` variant fetch.
-
#overlay_prefetch_request? ⇒ Boolean
True if the current request is a Turbo hover prefetch.
-
#overlay_request? ⇒ Boolean
True if the current request targets any configured overlay (initial open or in-overlay form re-render).
-
#popover_request? ⇒ Boolean
—– popover —–.
-
#turbo_overlay_align ⇒ Object
The per-link cross-axis alignment for popovers, parsed from the ‘X-Turbo-Overlay-Align` header.
-
#turbo_overlay_backdrop? ⇒ Boolean
Whether the current overlay request should render with a backdrop.
-
#turbo_overlay_close? ⇒ Boolean
Whether the current overlay request should render the chrome’s default close (“×”) button.
-
#turbo_overlay_frame_re_render? ⇒ Boolean
True when this is a form/link response targeting an existing overlay’s turbo-frame (form re-render in place).
-
#turbo_overlay_id ⇒ Object
The overlay id for the current request.
-
#turbo_overlay_initial_open? ⇒ Boolean
True for the initial open of an overlay (an ‘X-Turbo-Overlay` request that is not a form re-render inside an existing overlay frame).
-
#turbo_overlay_keep_open_on_redirect? ⇒ Boolean
Whether the overlay should stay open when a form descendant submits and the response is a redirect.
-
#turbo_overlay_layout ⇒ Object
Layout name for the current request.
-
#turbo_overlay_offset ⇒ Object
The per-link pixel offset between trigger and popover, parsed from the ‘X-Turbo-Overlay-Offset` header.
-
#turbo_overlay_position ⇒ Object
The per-link position override for the current overlay request, parsed from the ‘X-Turbo-Overlay-Position` header.
-
#turbo_overlay_type ⇒ Object
Returns ‘:modal`, `:drawer`, `:popover`, or `nil`.
Instance Method Details
#drawer_request? ⇒ Boolean
—– drawer —–
68 69 70 |
# File 'lib/turbo_overlay/controller.rb', line 68 def drawer_request? == :drawer end |
#hint_request? ⇒ Boolean
—– hint —–
80 81 82 |
# File 'lib/turbo_overlay/controller.rb', line 80 def hint_request? == :hint end |
#modal_request? ⇒ Boolean
—– modal —–
62 63 64 |
# File 'lib/turbo_overlay/controller.rb', line 62 def modal_request? == :modal end |
#overlay_hintable_request? ⇒ Boolean
True if the current request will use the hint template — either a hover prefetch (which the gem’s JS extracts the template from) or an explicit ‘:hint` variant fetch. Gates the `+hint` variant auto-render in `overlay_stack_tag`.
132 133 134 |
# File 'lib/turbo_overlay/controller.rb', line 132 def hint_request? || end |
#overlay_prefetch_request? ⇒ Boolean
True if the current request is a Turbo hover prefetch. Detected via the ‘X-Sec-Purpose: prefetch` request header that Turbo sends — the W3C `Sec-Purpose` is a Forbidden Header for JS-initiated `fetch()` requests, so Turbo prepends `X-`. Used by `overlay_stack_tag` to decide whether to render the action’s ‘+hint` variant template inline.
123 124 125 126 |
# File 'lib/turbo_overlay/controller.rb', line 123 def return false unless respond_to?(:request) && request request.headers["X-Sec-Purpose"].to_s.include?("prefetch") end |
#overlay_request? ⇒ Boolean
True if the current request targets any configured overlay (initial open or in-overlay form re-render). Useful in shared partials.
113 114 115 |
# File 'lib/turbo_overlay/controller.rb', line 113 def !.nil? end |
#popover_request? ⇒ Boolean
—– popover —–
74 75 76 |
# File 'lib/turbo_overlay/controller.rb', line 74 def popover_request? == :popover end |
#turbo_overlay_align ⇒ Object
The per-link cross-axis alignment for popovers, parsed from the ‘X-Turbo-Overlay-Align` header. Returns a Symbol (`:start`, `:center`, `:end`) or `nil`. Popover partials fall back to `TurboOverlay.configuration.popover.align`.
177 178 179 180 |
# File 'lib/turbo_overlay/controller.rb', line 177 def return @_turbo_overlay_align if defined?(@_turbo_overlay_align) @_turbo_overlay_align = end |
#turbo_overlay_backdrop? ⇒ Boolean
Whether the current overlay request should render with a backdrop. Defaults to ‘true`; only `false` when the link helper explicitly passed `backdrop: false` (carried in the `X-Turbo-Overlay-Backdrop` header). Drawer partials switch the `<dialog>` open mode and CSS based on this.
196 197 198 199 |
# File 'lib/turbo_overlay/controller.rb', line 196 def return @_turbo_overlay_backdrop if defined?(@_turbo_overlay_backdrop) @_turbo_overlay_backdrop = end |
#turbo_overlay_close? ⇒ Boolean
Whether the current overlay request should render the chrome’s default close (“×”) button. Defaults to ‘true`; only `false` when the link helper explicitly passed `close: false` (carried in the `X-Turbo-Overlay-Close` header). Chrome partials consult `overlay_close?` (view helper) which folds this into the full opt-out precedence chain.
207 208 209 210 |
# File 'lib/turbo_overlay/controller.rb', line 207 def return @_turbo_overlay_close if defined?(@_turbo_overlay_close) @_turbo_overlay_close = end |
#turbo_overlay_frame_re_render? ⇒ Boolean
True when this is a form/link response targeting an existing overlay’s turbo-frame (form re-render in place). Mirrors the same prefetch guard as ‘_resolve_overlay_type`: a hover prefetch carries the enclosing frame’s id in ‘Turbo-Frame` but is NOT a re-render — treating it as one would flip the response Content-Type to `text/vnd.turbo-stream.html` (via `_turbo_overlay_set_stream_content_type`) for a body that’s a plain ‘<turbo-frame>`, an incoherent mismatch.
241 242 243 244 245 |
# File 'lib/turbo_overlay/controller.rb', line 241 def return false unless respond_to?(:request) && request return false if request.headers["Turbo-Frame"].to_s.start_with?(OVERLAY_FRAME_PREFIX) end |
#turbo_overlay_id ⇒ Object
The overlay id for the current request. Resolution order:
-
‘X-Turbo-Overlay-Id` request header (caller supplied `overlay_id:` on the link helper)
-
The ‘<id>` segment parsed from a `Turbo-Frame: turbo_overlay_<type>_<id>` header (form re-render)
-
A freshly generated ‘SecureRandom.alphanumeric(8)` id, memoized for the duration of the request
Available in the controller and in views (e.g. for ‘turbo_stream.overlay(:close, id: turbo_overlay_id)`).
156 157 158 159 |
# File 'lib/turbo_overlay/controller.rb', line 156 def return @_turbo_overlay_id if defined?(@_turbo_overlay_id) @_turbo_overlay_id = end |
#turbo_overlay_initial_open? ⇒ Boolean
True for the initial open of an overlay (an ‘X-Turbo-Overlay` request that is not a form re-render inside an existing overlay frame). Used internally to decide between turbo-stream append wrapping and turbo-frame replace wrapping.
228 229 230 231 |
# File 'lib/turbo_overlay/controller.rb', line 228 def return false unless ! end |
#turbo_overlay_keep_open_on_redirect? ⇒ Boolean
Whether the overlay should stay open when a form descendant submits and the response is a redirect. Defaults to ‘false` (close-on-redirect is the gem’s default); becomes ‘true` when the trigger link passed `keep_overlay_open_on_redirect: true` (carried in the `X-Turbo-Overlay-Keep-Open` header). The chrome partials reflect this onto the `<dialog>` as a data attribute the per-dialog submit-end listener reads.
219 220 221 222 |
# File 'lib/turbo_overlay/controller.rb', line 219 def return @_turbo_overlay_keep_open if defined?(@_turbo_overlay_keep_open) @_turbo_overlay_keep_open = end |
#turbo_overlay_layout ⇒ Object
Layout name for the current request. Returns the matching overlay layout for overlay requests, ‘“turbo_rails/frame”` for plain turbo-frame requests (preserving Turbo’s optimization, since our auto-installed ‘layout` proc replaces Turbo’s), or ‘nil` otherwise so Rails picks the default layout.
Apps with a custom layout method should call this first:
def custom_layout
|| "my_app_layout"
end
97 98 99 100 101 102 103 104 105 106 |
# File 'lib/turbo_overlay/controller.rb', line 97 def case when :modal then "turbo_overlay/modal" when :drawer then "turbo_overlay/drawer" when :popover then "turbo_overlay/popover" when :hint then "turbo_overlay/hint" else "turbo_rails/frame" if respond_to?(:turbo_frame_request?) && turbo_frame_request? end end |
#turbo_overlay_offset ⇒ Object
The per-link pixel offset between trigger and popover, parsed from the ‘X-Turbo-Overlay-Offset` header. Returns an Integer or `nil`. Popover partials fall back to `TurboOverlay.configuration.popover.offset`.
186 187 188 189 |
# File 'lib/turbo_overlay/controller.rb', line 186 def return @_turbo_overlay_offset if defined?(@_turbo_overlay_offset) @_turbo_overlay_offset = end |
#turbo_overlay_position ⇒ Object
The per-link position override for the current overlay request, parsed from the ‘X-Turbo-Overlay-Position` header. Returns a Symbol (`:left`, `:right`, `:top`, `:bottom`) or `nil` when the link didn’t supply one. Drawer partials use this with a fallback to ‘TurboOverlay.configuration.drawer.position`; popover partials use it with a fallback to `TurboOverlay.configuration.popover.position`.
168 169 170 171 |
# File 'lib/turbo_overlay/controller.rb', line 168 def return @_turbo_overlay_position if defined?(@_turbo_overlay_position) @_turbo_overlay_position = end |
#turbo_overlay_type ⇒ Object
Returns ‘:modal`, `:drawer`, `:popover`, or `nil`. Detected from the `X-Turbo-Overlay` request header (initial open) or the `Turbo-Frame: turbo_overlay_<type>_<id>` header (form re-render inside an open overlay).
140 141 142 143 |
# File 'lib/turbo_overlay/controller.rb', line 140 def return @_turbo_overlay_type if defined?(@_turbo_overlay_type) @_turbo_overlay_type = end |