defmodule Turbolinks do @moduledoc """ This plug is built on top of works done by @kagux at https://github.com/kagux/turbolinks_plug in `web.ex` add `use Turbolinks` in `router.ex` add a the plug plug Turbolinks """ use Plug.Builder import Turbolinks.Helpers @session_key "turbolinks_location" @original_location_header "location" @location_header "turbolinks-location" @referrer_header "turbolinks-referrer" defmacro __using__(opts) do quote bind_quoted: [opts: opts] do import Phoenix.Controller, except: [redirect: 2] import Turbolinks.Helpers end end @doc false def call(conn, opts) do conn |> super(opts) |> register_before_send(&handle_redirect/1) |> put_phoenix_format() end @doc false defp handle_redirect(conn) do case conn.status do status when status in 301..302 -> store_location_in_session(conn) status when status in 200..299 -> restore_location_from_session(conn) _status -> conn end end defp store_location_in_session(conn) do with [_referrer] <- get_referrer_header(conn), [location] <- get_location_header(conn) do put_session(conn, @session_key, location) else [] -> conn end end defp restore_location_from_session(conn) do if location = get_session(conn, @session_key) do conn |> put_resp_header(@location_header, location) |> delete_session(@session_key) else conn end end defp get_location_header(conn) do get_resp_header(conn, @original_location_header) end defp get_referrer_header(conn) do get_req_header(conn, @referrer_header) end defp put_phoenix_format(conn) do if xhr?(conn) do Phoenix.Controller.put_format(conn, "js") else conn end end end