defmodule Drab.Modal do
require Logger
import Drab.{Query, Template}
@moduledoc """
Drab Module to launch Bootstrap Modals in the browser.
This module is optional and is not loaded by default. You need to explicitly declare it in the
commander:
use Drab.Commander, modules: [Drab.Modal]
This module requires jQuery installed as global, see
[README](https://hexdocs.pm/drab/readme.html#installation).
"""
use DrabModule
@impl true
def prerequisites(), do: [Drab.Query]
@impl true
def js_templates(), do: ["drab.modal.js"]
@doc """
Modal, synchronous alert box. This function shows bootstrap modal window on the browser and waits
for the user input.
Parameters:
* title - title of the message box
* body - html with the body of the alert box. When contains input, selects, etc, this function
return their values
Options:
* class - additional classes to .modal-dialog, ex. modal-lg, modal-sm, modal-xs
* buttons - list of name/text of the buttons (:ok, :cancel are only available names by default;
you need to create a template if you want more buttons), eq. [ok: "Yes", cancel: "No"]
* timeout - in milliseconds - after this time modal window will close and the function will
return {:cancel, _}
Returns a tuple {clicked_button, params}, where:
* clicked_button is an atom of `:ok` or `:cancel`. Notice that pressing `esc` or closing
the modal window will return :cancel, while pressing `enter` returns :ok
* params: Map `%{name|id => value}` of all inputs, selects, etc which are in the alert box body.
Uses `name` attribute as a key, or `id`, when there is no `name`, or `__undefined_[number]`,
when neither `id` or `name` are specified.
Examples:
socket |> alert("Title", "Shows this message with default OK button")
# Yes/No requester, returns :ok or :cancel
{button, _} = socket |> alert("Message", "Sure?", buttons: [ok: "Azaliż", cancel: "Ney"])
# messagebox with two input boxes in body
form = ""
name = case socket |> alert("What's your name?", form, buttons: [ok: "OK", cancel: "No"]) do
{ :ok, params } -> "\#{params["first"]} \#{params["second"]}"
{ :cancel, _ } -> "anonymous"
end
Templates used to generate HTML for the alert box could be found in
`deps/drab/priv/templates/drab/`. If you want to modify it, copy them to `priv/templates/drab`
in your application. There are two templates for default `:ok` and `:cancel` buttons, but
you may create new one and use them in the same way. For example, to have a new button called
`unspecified` create a template `priv/templates/drab/modal.alert.button.unspecified.html.eex`:
The button must have `drab-modal-button` class and its name should correspond to key in `buttons`
list. Now you can use your button in the same way as `:ok` and `:cancel`
{button, _} =
socket |> alert("3 buttons", "Choice?",
buttons: [ok: "Yes", cancel: "No", unspecified: "Don't know"])
"""
@spec alert(Phoenix.Socket.t(), String.t(), String.t(), Keyword.t()) :: Drab.Core.return() | no_return
@spec alert(Phoenix.Socket.t(), String.t(), String.t()) :: Drab.Core.return() | no_return
def alert(socket, title, body, options \\ []) do
buttons = options[:buttons] || [ok: "OK"]
bindings = [
title: title,
body: body,
class: options[:class],
buttons: buttons_html(socket, buttons)
]
html = render_template(socket.endpoint, "modal.alert.html.eex", bindings)
socket
|> delete("#_drab_modal")
|> insert(html, append: "body")
{:ok, result} =
Drab.push_and_wait_forever(socket, self(), "modal", timeout: options[:timeout])
result
end
@spec buttons_html(Phoenix.Socket.t(), Keyword.t()) :: String.t()
defp buttons_html(socket, buttons) do
buttons
|> Enum.map(fn {button, label} ->
render_template(socket.endpoint, "modal.alert.button.#{Atom.to_string(button)}.html.eex", label: label)
end)
|> Enum.join("\n")
end
end