Packages
flop_phoenix
0.5.0
0.26.1
0.26.0
0.25.3
0.25.2
0.25.1
0.25.0
0.24.1
0.24.0
0.23.1
0.23.0
0.22.10
0.22.9
0.22.8
0.22.7
0.22.6
0.22.5
0.22.4
0.22.3
0.22.2
0.22.1
0.22.0
0.21.2
0.21.1
0.21.0
0.20.0
0.19.1
0.19.0
0.18.2
0.18.1
0.18.0
0.17.2
0.17.1
0.17.0
0.16.0
0.15.2
0.15.1
0.15.0
0.14.2
0.14.1
0.14.0
0.13.0
0.12.0
0.11.1
0.11.0
0.10.0
0.9.1
0.9.0
0.8.1
0.8.0
0.7.0
0.6.1
0.6.0
0.5.1
0.5.0
0.4.0
0.3.0
0.2.0
0.1.0
Phoenix components for pagination, sortable tables and filter forms using Flop.
Current section
Files
Jump to
Current section
Files
lib/flop_phoenix/pagination.ex
defmodule Flop.Phoenix.Pagination do
@moduledoc false
use Phoenix.HTML
import Phoenix.LiveView.Helpers, only: [live_patch: 2]
alias Flop.Meta
@next_link_class "pagination-next"
@previous_link_class "pagination-previous"
@wrapper_class "pagination"
def init_opts(opts) do
Keyword.put_new(opts || [], :page_links, :all)
end
def build_attrs(opts) do
opts
|> Keyword.get(:wrapper_attrs, [])
|> Keyword.put_new(:class, @wrapper_class)
|> Keyword.put_new(:role, "navigation")
|> Keyword.put_new(:aria, label: "pagination")
end
def build_page_link_helper(meta, route_helper, route_helper_args) do
filter_map =
meta.flop.filters
|> Stream.with_index()
|> Enum.into(%{}, fn {filter, index} ->
{index, Map.from_struct(filter)}
end)
query_params =
[]
|> maybe_add_param(:filters, filter_map)
|> maybe_add_param(:order_by, meta.flop.order_by)
|> maybe_add_param(:order_directions, meta.flop.order_directions)
|> maybe_add_param(:page_size, meta.page_size)
fn page ->
apply(
route_helper,
route_helper_args ++ [Keyword.put(query_params, :page, page)]
)
end
end
@spec previous_link(Meta.t(), function, keyword) :: Phoenix.HTML.safe()
def previous_link(%Meta{} = meta, page_link_helper, opts) do
attrs =
opts
|> Keyword.get(:previous_link_attrs, [])
|> Keyword.put_new(:class, @previous_link_class)
content = opts[:previous_link_content] || "Previous"
if meta.has_previous_page? do
attrs = Keyword.put(attrs, :to, page_link_helper.(meta.previous_page))
if opts[:live_view] do
live_patch attrs do
content
end
else
link attrs do
content
end
end
else
attrs = Keyword.put(attrs, :disabled, "disabled")
content_tag :span, attrs do
content
end
end
end
@spec next_link(Meta.t(), function, keyword) :: Phoenix.HTML.safe()
def next_link(%Meta{} = meta, page_link_helper, opts) do
attrs =
opts
|> Keyword.get(:next_link_attrs, [])
|> Keyword.put_new(:class, @next_link_class)
content = opts[:next_link_content] || "Next"
if meta.has_next_page? do
attrs = Keyword.put(attrs, :to, page_link_helper.(meta.next_page))
if opts[:live_view] do
live_patch attrs do
content
end
else
link attrs do
content
end
end
else
attrs = Keyword.put(attrs, :disabled, "disabled")
content_tag :span, attrs do
content
end
end
end
@spec page_links(Meta.t(), function, keyword) :: Phoenix.HTML.safe()
def page_links(meta, route_func, opts) do
page_link_opt = Keyword.fetch!(opts, :page_links)
case page_link_opt do
:hide ->
raw(nil)
:all ->
render_page_links(meta, route_func, meta.total_pages, opts)
{:ellipsis, max_pages} ->
render_page_links(meta, route_func, max_pages, opts)
end
end
defp render_page_links(meta, route_func, max_pages, opts) do
aria_label = opts[:pagination_link_aria_label] || (&"Goto page #{&1}")
link_attrs =
opts
|> Keyword.get(:pagination_link_attrs, [])
|> Keyword.put_new(:class, "pagination-link")
|> Keyword.put_new(:aria, [])
list_attrs =
opts
|> Keyword.get(:pagination_list_attrs, [])
|> Keyword.put_new(:class, "pagination-list")
ellipsis_class =
opts
|> Keyword.get(:ellipsis_attrs, [])
|> Keyword.put_new(:class, "pagination-ellipsis")
ellipsis_content = Keyword.get(opts, :ellipsis_content, raw("…"))
first..last =
range =
get_page_link_range(meta.current_page, max_pages, meta.total_pages)
start_ellipsis =
if first > 2,
do: pagination_ellipsis(ellipsis_class, ellipsis_content),
else: raw(nil)
end_ellipsis =
if last < meta.total_pages - 1,
do: pagination_ellipsis(ellipsis_class, ellipsis_content),
else: raw(nil)
link_func =
if opts[:live_view],
do: &live_patch/2,
else: &link/2
first_link =
if first > 1,
do:
page_link_tag(1, meta, link_attrs, aria_label, route_func, link_func),
else: raw(nil)
last_link =
if last < meta.total_pages,
do:
page_link_tag(
meta.total_pages,
meta,
link_attrs,
aria_label,
route_func,
link_func
),
else: raw(nil)
links =
for page <- range do
page_link_tag(page, meta, link_attrs, aria_label, route_func, link_func)
end
content_tag :ul, list_attrs do
[
first_link,
start_ellipsis,
links,
end_ellipsis,
last_link
]
end
end
defp page_link_tag(
page,
meta,
link_attrs,
aria_label,
route_func,
link_func
) do
attrs =
link_attrs
|> Keyword.update!(
:aria,
&Keyword.put(&1, :label, aria_label.(page))
)
|> add_current_attrs(meta.current_page == page)
|> Keyword.put(:to, route_func.(page))
content_tag :li do
link_func.(page, attrs)
end
end
defp get_page_link_range(current_page, max_pages, total_pages) do
# number of additional pages to show before or after current page
additional = ceil(max_pages / 2)
cond do
max_pages >= total_pages ->
1..total_pages
current_page + additional >= total_pages ->
(total_pages - max_pages + 1)..total_pages
true ->
first = max(current_page - additional + 1, 1)
last = min(first + max_pages - 1, total_pages)
first..last
end
end
defp pagination_ellipsis(attrs, content) do
content_tag :li do
content_tag :span, attrs do
content
end
end
end
defp add_current_attrs(attrs, false), do: attrs
defp add_current_attrs(attrs, true) do
attrs
|> Keyword.update!(:aria, &Keyword.put(&1, :current, "page"))
|> Keyword.update!(:class, &"#{&1} is-current")
end
defp maybe_add_param(params, _, nil), do: params
defp maybe_add_param(params, _, []), do: params
defp maybe_add_param(params, key, value), do: Keyword.put(params, key, value)
end