diff --git a/Gemfile b/Gemfile index d7ca8502b3b..ed8007fb5b2 100644 --- a/Gemfile +++ b/Gemfile @@ -37,6 +37,7 @@ gem 'unicode_utils', '>=1.4.0' gem "lograge" # https://github.com/roidrage/lograge gem 'will_paginate', '>=3.0.2' +gem "pagy", "~> 9.3" gem 'acts_as_list', '~> 0.9.7' gem 'akismetor' diff --git a/Gemfile.lock b/Gemfile.lock index d354f0821ce..8cb4ce7f6da 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -402,6 +402,7 @@ GEM mini_portile2 (~> 2.8.2) racc (~> 1.4) orm_adapter (0.5.0) + pagy (9.3.3) parallel (1.25.1) parser (3.3.0.5) ast (~> 2.4.1) @@ -701,6 +702,7 @@ DEPENDENCIES mysql2 n_plus_one_control nokogiri (>= 1.8.5) + pagy (~> 9.3) permit_yo phraseapp-in-context-editor-ruby (>= 1.0.6) pickle diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 89a98aa6b0c..f1592640c8e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -42,6 +42,30 @@ def sanitize_ac_params end end + include Pagy::Backend + def pagy(collection, **vars) + pagy_overflow_handler do + super + end + end + + def pagy_query_result(query_result, **vars) + pagy_overflow_handler do + Pagy.new( + count: query_result.total_entries, + page: query_result.current_page, + limit: query_result.per_page, + **vars + ) + end + end + + def pagy_overflow_handler(*) + yield + rescue Pagy::OverflowError + nil + end + def display_auth_error respond_to do |format| format.html do diff --git a/app/controllers/bookmarks_controller.rb b/app/controllers/bookmarks_controller.rb index 32658a750d1..cdccaa91606 100644 --- a/app/controllers/bookmarks_controller.rb +++ b/app/controllers/bookmarks_controller.rb @@ -145,6 +145,13 @@ def index end end set_own_bookmarks + + @pagy = + if @bookmarks.respond_to?(:total_pages) + pagy_query_result(@bookmarks) + elsif @bookmarkable_items.respond_to?(:total_pages) + pagy_query_result(@bookmarkable_items) + end end # GET /:locale/bookmark/:id diff --git a/app/controllers/readings_controller.rb b/app/controllers/readings_controller.rb index 12e1676bdcb..bfe189f0a93 100644 --- a/app/controllers/readings_controller.rb +++ b/app/controllers/readings_controller.rb @@ -16,7 +16,8 @@ def index @readings = @readings.where(toread: true) @page_subtitle = ts("Marked For Later") end - @readings = @readings.order("last_viewed DESC").page(params[:page]) + @readings = @readings.order("last_viewed DESC") + @pagy, @readings = pagy(@readings) end def destroy diff --git a/app/controllers/works_controller.rb b/app/controllers/works_controller.rb index d87f5fb0596..8e73e26464f 100755 --- a/app/controllers/works_controller.rb +++ b/app/controllers/works_controller.rb @@ -131,6 +131,8 @@ def index @works = Work.latest.for_blurb.to_a end set_own_works + + @pagy = pagy_query_result(@works) if @works.respond_to?(:total_pages) end def collected diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2a2cf4b6f0f..554e8c5863f 100755 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -516,18 +516,6 @@ def first_paragraph(full_text, placeholder_text = 'No preview available.') end end - # change the default link renderer for will_paginate - def will_paginate(collection_or_options = nil, options = {}) - if collection_or_options.is_a? Hash - options = collection_or_options - collection_or_options = nil - end - unless options[:renderer] - options = options.merge renderer: PaginationListLinkRenderer - end - super(*[collection_or_options, options].compact) - end - # spans for nesting a checkbox or radio button inside its label to make custom # checkbox or radio designs def label_indicator_and_text(text) diff --git a/app/helpers/pagination_helper.rb b/app/helpers/pagination_helper.rb new file mode 100644 index 00000000000..cee1c0bfe95 --- /dev/null +++ b/app/helpers/pagination_helper.rb @@ -0,0 +1,66 @@ +module PaginationHelper + include Pagy::Frontend + + # change the default link renderer for will_paginate + def will_paginate(collection_or_options = nil, options = {}) + if collection_or_options.is_a? Hash + options = collection_or_options + collection_or_options = nil + end + options = options.merge renderer: PaginationListLinkRenderer unless options[:renderer] + super(*[collection_or_options, options].compact) + end + + # Cf https://github.com/ddnexus/pagy/blob/master/gem/lib/pagy/frontend.rb + # i18n-tasks-use t("pagy.prev") + # i18n-tasks-use t("pagy.next") + # i18n-tasks-use t("pagy.aria_label.nav") + def pagy_nav(pagy, id: nil, aria_label: nil, **vars) + return nil unless pagy + + # Keep will_paginate behavior of showing nothing if only one page + return nil if pagy.series.length <= 1 + + id = %( id="#{id}") if id + a = pagy_anchor(pagy, **vars) + + html = %(

#{t('a11y.navigation')}

) + + html << %() + + prev_text = pagy_t("pagy.prev") + prev_a = + if (p_prev = pagy.prev) + a.call(p_prev, prev_text) + else + %(#{prev_text}) + end + html << %() + + pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36] + html << %(
  • ) + html << case item + when Integer + a.call(item) + when String + %(#{pagy.label_for(item)}) + when :gap + %(#{pagy_t('pagy.gap')}) + else + raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}" + end + html << %(
  • ) + end + + next_text = pagy_t("pagy.next") + next_a = + if (p_next = pagy.next) + a.call(p_next, next_text) + else + %(#{next_text}) + end + html << %() + + html << %() + end +end diff --git a/app/views/bookmarks/index.html.erb b/app/views/bookmarks/index.html.erb index 0eac4c5be70..2ada8707eb7 100755 --- a/app/views/bookmarks/index.html.erb +++ b/app/views/bookmarks/index.html.erb @@ -49,11 +49,7 @@

    <%= ts("These are some of the latest bookmarks created on the Archive. To find more bookmarks, #{link_to 'choose a fandom', media_path} or #{link_to 'try our advanced search', search_bookmarks_path}.").html_safe %> <% end %> -<% if @bookmarks.respond_to?(:total_pages) %> - <%= will_paginate @bookmarks %> -<% elsif @bookmarkable_items.respond_to?(:total_pages) %> - <%= will_paginate @bookmarkable_items %> -<% end %> +<%== pagy_nav @pagy %>

    <%= ts("List of Bookmarks") %>

    @@ -71,9 +67,5 @@ -<% if @bookmarks.respond_to?(:total_pages) %> - <%= will_paginate @bookmarks %> -<% elsif @bookmarkable_items.respond_to?(:total_pages) %> - <%= will_paginate @bookmarkable_items %> -<% end %> +<%== pagy_nav @pagy %> diff --git a/app/views/readings/index.html.erb b/app/views/readings/index.html.erb index 9d0e236cd50..90d1969dcd3 100644 --- a/app/views/readings/index.html.erb +++ b/app/views/readings/index.html.erb @@ -30,5 +30,5 @@ -<%= will_paginate @readings %> +<%== pagy_nav @pagy %> diff --git a/app/views/works/index.html.erb b/app/views/works/index.html.erb index bf4bec88222..8ff441f4172 100755 --- a/app/views/works/index.html.erb +++ b/app/views/works/index.html.erb @@ -46,9 +46,7 @@

    <%= ts("These are some of the latest works posted to the Archive. To find more works, #{link_to 'choose a fandom', media_path} or #{link_to 'try our advanced search', search_works_path}.").html_safe %> <% end %> -<% if @works.respond_to?(:total_pages) %> - <%= will_paginate @works %> -<% end %> +<%== pagy_nav @pagy %>

    <%= ts("Listing Works") %>

    @@ -64,6 +62,4 @@ <% end %> -<% if @works.respond_to?(:total_pages) %> - <%= will_paginate @works %> -<% end %> +<%== pagy_nav @pagy %> diff --git a/config/brakeman.yml b/config/brakeman.yml index 7890bda2d90..28e6a3b34c0 100644 --- a/config/brakeman.yml +++ b/config/brakeman.yml @@ -1,3 +1,4 @@ --- :safe_methods: +- :pagy_nav - :sanitize_field diff --git a/config/initializers/gem-plugin_config/pagy.rb b/config/initializers/gem-plugin_config/pagy.rb new file mode 100644 index 00000000000..62acb3685c2 --- /dev/null +++ b/config/initializers/gem-plugin_config/pagy.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# https://ddnexus.github.io/pagy/docs/extras/i18n/ +require "pagy/extras/i18n" + +# See https://ddnexus.github.io/pagy/docs/api/pagy#variables +Pagy::DEFAULT[:limit] = ArchiveConfig.ITEMS_PER_PAGE +Pagy::DEFAULT[:size] = 9 + +Pagy::DEFAULT.freeze diff --git a/config/locales/views/en.yml b/config/locales/views/en.yml index 4cbc8c0438a..bcd303d2711 100644 --- a/config/locales/views/en.yml +++ b/config/locales/views/en.yml @@ -1565,6 +1565,11 @@ en: orphan_user: orphaning_bylines_only_message_html: Orphaning will automatically remove your personal information from bylines only. It will not automatically remove your personal information from anywhere else in the work(s). Social media accounts, contact information, email addresses, names, and any other personal information posted in the title, summary, notes, tags, work body, or comment text will not be automatically removed. Comments posted by other users will also not be affected by Orphaning. If you want information removed from these places, you should edit or delete it prior to Orphaning. Once you Orphan the work(s), you will no longer be able to delete information in these places yourself. orphaning_works_message_html: 'Orphaning will permanently remove your username and/or pseud from the bylines of: the following work(s), their chapters, associated series, and any comments you may have left on them while logged into this account.' + pagy: + aria_label: + nav: Pagination + next: Next → + prev: "← Previous" preferences: index: allow_collection_invitation: Allow others to invite my works to collections.