Current section

Files

Jump to
phoenix_live_view lib phoenix_live_view plug.ex
Raw

lib/phoenix_live_view/plug.ex

defmodule Phoenix.LiveView.Plug do
@moduledoc false
alias Phoenix.LiveView.Controller
@behaviour Plug
@link_header "x-requested-with"
def link_header, do: @link_header
@impl Plug
def init(view) when is_atom(view), do: view
def init({view, opts}) when is_atom(view) and is_list(opts) do
{view, __live_opts__(opts)}
end
@impl Plug
def call(%Plug.Conn{private: %{phoenix_live_view: opts}} = conn, view) when is_atom(view) do
do_call(conn, view, opts)
end
def call(%Plug.Conn{} = conn, {view, opts}) when is_atom(view) and is_list(opts) do
do_call(conn, view, opts)
end
defp do_call(conn, view, opts) do
render_opts = Keyword.take(opts, [:container, :router, :session])
if live_link?(conn) do
html = Phoenix.LiveView.Static.container_render(conn, view, render_opts)
conn
|> put_cache_headers()
|> Plug.Conn.put_resp_header(@link_header, "live-link")
|> Phoenix.Controller.html(html)
else
conn
|> put_new_layout_from_router(opts)
|> Controller.live_render(view, render_opts)
end
end
@doc false
def put_cache_headers(conn) do
conn
|> Plug.Conn.put_resp_header("vary", @link_header)
|> Plug.Conn.put_resp_header(
"cache-control",
"max-age=0, no-cache, no-store, must-revalidate, post-check=0, pre-check=0"
)
end
defp put_new_layout_from_router(conn, opts) do
cond do
live_link?(conn) -> Phoenix.Controller.put_layout(conn, false)
layout = opts[:layout] -> Phoenix.Controller.put_new_layout(conn, layout)
true -> conn
end
end
defp live_link?(%Plug.Conn{} = conn) do
Plug.Conn.get_req_header(conn, @link_header) == ["live-link"]
end
def __live_opts__(opts) do
router = Keyword.fetch!(opts, :router)
new_opts =
opts
|> Keyword.put_new_lazy(:layout, fn ->
layout_view =
router
|> Atom.to_string()
|> String.split(".")
|> Enum.drop(-1)
|> Kernel.++(["LayoutView"])
|> Module.concat()
{layout_view, :app}
end)
new_opts
end
end