Packages
corex
0.1.2
0.1.2
0.1.1
0.1.0
0.1.0-rc.1
0.1.0-rc.0
0.1.0-beta.5
0.1.0-beta.4
0.1.0-beta.3
0.1.0-beta.2
0.1.0-beta.1
0.1.0-alpha.33
0.1.0-alpha.32
0.1.0-alpha.31
0.1.0-alpha.30
0.1.0-alpha.29
0.1.0-alpha.28
0.1.0-alpha.27
0.1.0-alpha.26
0.1.0-alpha.25
0.1.0-alpha.24
0.1.0-alpha.23
0.1.0-alpha.22
0.1.0-alpha.21
0.1.0-alpha.20
0.1.0-alpha.19
0.1.0-alpha.18
0.1.0-alpha.17
0.1.0-alpha.16
0.1.0-alpha.15
0.1.0-alpha.14
0.1.0-alpha.13
0.1.0-alpha.12
0.1.0-alpha.11
0.1.0-alpha.10
0.1.0-alpha.9
0.1.0-alpha.8
0.1.0-alpha.7
0.1.0-alpha.6
0.1.0-alpha.5
0.1.0-alpha.4
0.1.0-alpha.3
0.1.0-alpha.2
0.1.0-alpha.1
Accessible and unstyled UI components library written in Elixir and TypeScript that integrates Zag.js state machines into the Phoenix Framework.
Current section
Files
Jump to
Current section
Files
lib/components/pagination/utils.ex
defmodule Corex.Pagination.Utils do
@moduledoc false
@type page_entry :: %{type: :page, value: pos_integer()} | %{type: :ellipsis}
@spec pages(pos_integer(), pos_integer(), pos_integer(), pos_integer()) :: [page_entry()]
def pages(page, total_pages, sibling_count, boundary_count) do
page
|> get_range(total_pages, sibling_count, boundary_count)
|> transform()
end
defp get_range(_page, total_pages, _sibling_count, _boundary_count) when total_pages <= 0,
do: []
defp get_range(_page, 1, _sibling_count, _boundary_count), do: [1]
defp get_range(page, total_pages, sibling_count, boundary_count) do
max_visible = sibling_count * 2 + 3 + boundary_count * 2
if total_pages <= max_visible do
range(1, total_pages)
else
page
|> sparse_pages(total_pages, sibling_count, boundary_count, max_visible)
|> collapse_adjacent_ellipsis(total_pages)
end
end
defp sparse_pages(page, total_pages, sibling_count, boundary_count, max_visible) do
first = 1
last = total_pages
left_sibling = max(page - sibling_count, first)
right_sibling = min(page + sibling_count, last)
item_count = max_visible - 1 - boundary_count
show_left? = show_left_ellipsis?(left_sibling, first, boundary_count)
show_right? = show_right_ellipsis?(right_sibling, last, boundary_count)
build_sparse_pages(
first,
last,
left_sibling,
right_sibling,
boundary_count,
item_count,
show_left?,
show_right?
)
end
defp show_left_ellipsis?(left_sibling, first, boundary_count) do
left_sibling > first + boundary_count + 1 and
abs(left_sibling - first) > boundary_count + 1
end
defp show_right_ellipsis?(right_sibling, last, boundary_count) do
right_sibling < last - boundary_count - 1 and abs(last - right_sibling) > boundary_count + 1
end
defp build_sparse_pages(
first,
last,
left_sibling,
right_sibling,
boundary_count,
item_count,
show_left?,
show_right?
) do
cond do
not show_left? and show_right? ->
range(1, item_count) ++ [:ellipsis] ++ range(last - boundary_count + 1, last)
show_left? and not show_right? ->
range(first, first + boundary_count - 1) ++
[:ellipsis] ++ range(last - item_count + 1, last)
show_left? and show_right? ->
range(first, first + boundary_count - 1) ++
[:ellipsis] ++
range(left_sibling, right_sibling) ++
[:ellipsis] ++ range(last - boundary_count + 1, last)
true ->
range(first, last)
end
end
defp collapse_adjacent_ellipsis(pages, total_pages) do
Enum.map(Enum.with_index(pages), fn
{:ellipsis, index} -> collapse_ellipsis(pages, index, total_pages)
{value, _index} -> value
end)
end
defp collapse_ellipsis(pages, index, total_pages) do
prev_page = pages |> Enum.at(index - 1) |> page_number(0)
next_page = pages |> Enum.at(index + 1) |> page_number(total_pages + 1)
if next_page - prev_page == 2, do: prev_page + 1, else: :ellipsis
end
defp page_number(page, _fallback) when is_integer(page), do: page
defp page_number(_entry, fallback), do: fallback
defp range(start, finish) when start <= finish, do: Enum.to_list(start..finish)
defp range(_start, _finish), do: []
defp transform(items) do
Enum.map(items, fn
value when is_integer(value) -> %{type: :page, value: value}
:ellipsis -> %{type: :ellipsis}
end)
end
@spec format_item_label(String.t() | nil, pos_integer(), pos_integer()) :: String.t() | nil
def format_item_label(nil, _, _), do: nil
def format_item_label(template, page, total_pages) when is_binary(template) do
template
|> String.replace("%{page}", to_string(page))
|> String.replace("%{total_pages}", to_string(total_pages))
end
@spec page_href(String.t(), String.t(), String.t(), pos_integer(), pos_integer()) ::
String.t() | nil
def page_href(base, page_param, page_size_param, page, page_size) do
if Corex.Url.allowed_href?(base) do
sep = if String.contains?(base, "?"), do: "&", else: "?"
encoded_page = URI.encode_www_form(page_param)
encoded_size = URI.encode_www_form(page_size_param)
"#{base}#{sep}#{encoded_page}=#{page}&#{encoded_size}=#{page_size}"
end
end
end