views: factor out paginator component.
* Refactor the paginator into a ViewComponent.
* Fix inconsistent spacing between paginator items.
* Fix a bug where the sequential paginator generated the wrong next /
previous page links in the <link rel="{next|prev}"> tags in the <head>.
* Always include the final page as a hidden html element, so that it can
be unhidden with custom CSS.
* Make it easier to change the pagination window.
This commit is contained in:
@@ -50,4 +50,19 @@ module ComponentsHelper
|
||||
tags = TagListComponent.tags_from_names(tag_names)
|
||||
render TagListComponent.new(tags: tags, **options).with_variant(:search)
|
||||
end
|
||||
|
||||
# The <link rel="next"> / <link rel="prev"> links in the <meta> element of the <head>.
|
||||
def render_meta_links(records)
|
||||
render PaginatorComponent.new(records: records, params: params).with_variant(:meta_links)
|
||||
end
|
||||
|
||||
def numbered_paginator(records)
|
||||
paginator = PaginatorComponent.new(records: records, params: params)
|
||||
|
||||
if paginator.use_sequential_paginator?
|
||||
render paginator.with_variant(:sequential)
|
||||
else
|
||||
render paginator.with_variant(:numbered)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
module PaginationHelper
|
||||
def sequential_paginator(records)
|
||||
html = '<div class="paginator"><menu>'
|
||||
|
||||
if records.any?
|
||||
if params[:page] =~ /[ab]/ && !records.is_first_page?
|
||||
html << '<li>' + link_to("< Previous", nav_params_for("a#{records[0].id}"), rel: "prev", id: "paginator-prev", "data-shortcut": "a left") + '</li>'
|
||||
end
|
||||
|
||||
unless records.is_last_page?
|
||||
html << '<li>' + link_to("Next >", nav_params_for("b#{records[-1].id}"), rel: "next", id: "paginator-next", "data-shortcut": "d right") + '</li>'
|
||||
end
|
||||
end
|
||||
|
||||
html << "</menu></div>"
|
||||
html.html_safe
|
||||
end
|
||||
|
||||
def use_sequential_paginator?(records, page_limit)
|
||||
params[:page] =~ /[ab]/ || records.current_page >= page_limit
|
||||
end
|
||||
|
||||
def numbered_paginator(records, page_limit: CurrentUser.user.page_limit)
|
||||
if use_sequential_paginator?(records, page_limit)
|
||||
return sequential_paginator(records)
|
||||
end
|
||||
|
||||
html = '<div class="paginator"><menu>'
|
||||
window = 4
|
||||
|
||||
if records.current_page >= 2
|
||||
html << "<li class='arrow'>" + link_to(chevron_left_icon, nav_params_for(records.current_page - 1), rel: "prev", id: "paginator-prev", "data-shortcut": "a left") + "</li>"
|
||||
else
|
||||
html << "<li class='arrow'><span>" + chevron_left_icon + "</span></li>"
|
||||
end
|
||||
|
||||
if records.total_pages <= (window * 2) + 5
|
||||
1.upto(records.total_pages) do |page|
|
||||
html << numbered_paginator_item(page, records.current_page, page_limit)
|
||||
end
|
||||
|
||||
elsif records.current_page <= window + 2
|
||||
1.upto(records.current_page + window) do |page|
|
||||
html << numbered_paginator_item(page, records.current_page, page_limit)
|
||||
end
|
||||
html << numbered_paginator_item("...", records.current_page, page_limit)
|
||||
html << numbered_paginator_final_item(records.total_pages, records.current_page, page_limit)
|
||||
elsif records.current_page >= records.total_pages - (window + 1)
|
||||
html << numbered_paginator_item(1, records.current_page, page_limit)
|
||||
html << numbered_paginator_item("...", records.current_page, page_limit)
|
||||
(records.current_page - window).upto(records.total_pages) do |page|
|
||||
html << numbered_paginator_item(page, records.current_page, page_limit)
|
||||
end
|
||||
else
|
||||
html << numbered_paginator_item(1, records.current_page, page_limit)
|
||||
html << numbered_paginator_item("...", records.current_page, page_limit)
|
||||
if records.present?
|
||||
right_window = records.current_page + window
|
||||
else
|
||||
right_window = records.current_page
|
||||
end
|
||||
(records.current_page - window).upto(right_window) do |page|
|
||||
html << numbered_paginator_item(page, records.current_page, page_limit)
|
||||
end
|
||||
if records.present?
|
||||
html << numbered_paginator_item("...", records.current_page, page_limit)
|
||||
html << numbered_paginator_final_item(records.total_pages, records.current_page, page_limit)
|
||||
end
|
||||
end
|
||||
|
||||
if records.current_page < records.total_pages && records.present?
|
||||
html << "<li class='arrow'>" + link_to(chevron_right_icon, nav_params_for(records.current_page + 1), rel: "next", id: "paginator-next", "data-shortcut": "d right") + "</li>"
|
||||
else
|
||||
html << "<li class='arrow'><span>" + chevron_right_icon + "</span></li>"
|
||||
end
|
||||
|
||||
html << "</menu></div>"
|
||||
html.html_safe
|
||||
end
|
||||
|
||||
def numbered_paginator_final_item(total_pages, current_page, page_limit)
|
||||
if total_pages <= page_limit
|
||||
numbered_paginator_item(total_pages, current_page, page_limit)
|
||||
else
|
||||
""
|
||||
end
|
||||
end
|
||||
|
||||
def numbered_paginator_item(page, current_page, page_limit)
|
||||
return "" if page.to_i > page_limit
|
||||
|
||||
html = []
|
||||
if page == "..."
|
||||
html << "<li class='more'>"
|
||||
html << ellipsis_icon
|
||||
html << "</li>"
|
||||
elsif page == current_page
|
||||
html << "<li class='current-page'>"
|
||||
html << '<span>' + page.to_s + '</span>'
|
||||
html << "</li>"
|
||||
else
|
||||
html << "<li class='numbered-page'>"
|
||||
html << link_to(page, nav_params_for(page))
|
||||
html << "</li>"
|
||||
end
|
||||
html.join.html_safe
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def nav_params_for(page)
|
||||
query_params = params.except(:controller, :action, :id).merge(page: page).permit!
|
||||
{ params: query_params }
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user