defmodule SimplePagination.PaginationHelper do
@moduledoc """
contains helper functions to create
- order_by buttons
- page links
- filters
"""
use Phoenix.Component
alias SimplePagination.PaginatorState
# attr :label, :string, required: true
@doc """
provides a link to order following a given field
<.order_tag label="id" order_by={:id} paginator={@things} />
"""
def order_tag(
%{label: label, order_by: order_by, paginator: %PaginatorState{} = paginator} = assigns
) do
# IO.inspect(_w?: {__MODULE__, :order_tag}, paginator_order: paginator.order_by)
arrow = order_arrow_indicator(paginator, order_by)
~H"""
<a href="#" phx-click="paginate", phx-value-order_by={@order_by}><%= label %></a><%= arrow %>
"""
end
defp order_arrow_indicator(%PaginatorState{order_by: {direction, field}}, tag_order_by_field)
when field == tag_order_by_field do
case direction do
:asc -> " (asc)"
_ -> " (desc)"
end
end
defp order_arrow_indicator(_, _), do: ""
@doc """
provides links for pages 1...N and a select box for number of items per page
"""
def page_tag(%{paginator: %PaginatorState{} = pg} = assigns) do
# IO.inspect(_w?: {__MODULE__, :page_tag}, page: pg.page)
delta = Map.get(assigns, :delta, 1)
~H"""
<div class="paginator pager" style="">
<%= page_indicators(@paginator.page, @paginator.page_max, delta) %>
<form id="paginator" phx-change="paginate" style="display: inline">
<select name="per_page_nb">
<%= for pnb <- @paginator.per_page_items do %>
<%= per_page_tag_option(pnb, pg.per_page_nb) %>
<% end %>
</select>
</form>
</div>
"""
end
defp per_page_tag_option(per_page_nb, per_page_nb_current, options \\ %{}) do
default = if per_page_nb == per_page_nb_current, do: " selected", else: ""
label = if per_page_nb == 0, do: Map.get(options, :all_label, "All"), else: per_page_nb
"""
<option value=#{per_page_nb}#{default}>#{label}</option>
"""
|> Phoenix.HTML.raw()
end
# displays a block of page numbers unless there's only one page
def page_indicators(_page, 1, _), do: ""
def page_indicators(page, page_nb, delta) do
# get the boundaries of the window showing the current page
w_start = max(1, page - delta)
w_end = min(page_nb, page + delta)
1..page_nb
# 1, 2, 3, 4, 5, 6, 7, 8, 9 (e.g. page=4, delta=1)
|> Enum.map(fn e ->
if (e > 1 and e < w_start) or (e > w_end and e < page_nb), do: :space, else: e
end)
# 1, :space, :space, 3, 4, 5, :space, :space, :space, 9
|> Enum.dedup()
# 1, :space, 3, 4, 5, :space, 9
|> Enum.reduce("", fn p, acc -> acc <> page_indicator(p, page, page_nb) end)
|> Phoenix.HTML.raw()
end
defp page_indicator(page_nb, page_nb_current, page_max) do
css_class =
"paginator pager-page" <>
case page_nb do
1 -> " first"
^page_max -> " last"
_ -> ""
end
case page_nb do
:space ->
"""
<span class="#{css_class} spacer">…</span>
"""
^page_nb_current ->
"""
<span class="#{css_class} current">#{page_nb}</span>
"""
_ ->
"""
<a href="#" phx-click="paginate" phx-value-page=#{page_nb} class="#{css_class}">#{page_nb}</a>
"""
end
end
# === FILTER
def search_filter_tag(assigns) do
btn_label = Map.get(assigns, :label, "Go!")
~H"""
<form id={"paginator-search"} phx-submit="paginate" class="paginator search-form">
<%= for {f, v} <- @paginator.filters do %>
<input type="search" name={"filters[#{f}]"} placeholder={f} value={"#{v}"}>
<% end %>
<button type="submit"><%= btn_label %></button>
</form>
"""
end
end