defmodule HaytniWeb.Shared do @moduledoc ~S""" Contains shared stuffs between Haytni base plugins. Mainly handle a message view/template which is intended to replace "abusive" `Phoenix.Controller.put_flash/3`. `put_flash` stores messages in session and may have several issues: * it can conflict if you use multiple tabs or instances of a same browser * excessive reads/writes (depending on the backend) * incompatible with HTTP caching """ use HaytniWeb, :controller @doc ~S""" Momorize the original HTTP referer by adding it to a changeset. Have to be called on `new` or `edit` action (not `create` nor `update`). """ @spec add_referer_to_changeset(conn :: Plug.Conn.t, changeset :: Ecto.Changeset.t) :: Ecto.Changeset.t def add_referer_to_changeset(conn = %Plug.Conn{}, changeset = %Ecto.Changeset{}) do referer = with [referer] <- Plug.Conn.get_req_header(conn, "referer") do referer else _ -> nil end Ecto.Changeset.put_change(changeset, :referer, referer) end @doc ~S""" Add a back/cancel link for MessageView. NOTE: we do not use `"javascript:history.back()"` as default since this may be inappropriate with Content Security Policy (CSP). But user is free to use it by indicating it as value for *default*. """ @spec back_link(conn :: Plug.Conn.t, struct :: struct, default :: String.t) :: Plug.Conn.t def back_link(conn = %Plug.Conn{}, struct = %_{}, default) do back_link = with referer when not is_nil(referer) <- Map.get(struct, :referer), host = Keyword.get(Module.concat([Haytni.web_module(), :Endpoint]).config(:url), :host, "localhost"), %URI{host: ^host, scheme: scheme} when scheme in ~W[http https] <- URI.parse(referer) do referer else _ -> nil end || default || "/" conn |> assign(:back_link, back_link) end @doc ~S""" Add a next step link for MessageView. """ @spec next_step_link(conn :: Plug.Conn.t, href :: String.t, text :: String.t) :: Plug.Conn.t def next_step_link(conn = %Plug.Conn{}, href, text) do conn |> assign(:next_step_link_text, text) |> assign(:next_step_link_href, href) end @doc ~S""" Set connection to render MessageView/message.html. """ @spec render_message(conn :: Plug.Conn.t, message :: String.t, type :: atom) :: Plug.Conn.t def render_message(conn = %Plug.Conn{}, message, type \\ :info) do conn |> assign(:type, type) |> assign(:message, message) |> put_view(Module.concat([Haytni.web_module(), :Haytni, :SharedView])) |> render("message.html") end end