# See Pagy::Frontend API documentation: https://ddnexus.github.io/pagy/api/frontend
# frozen_string_literal: true
require 'yaml'
class Pagy
# All the code here has been optimized for performance: it may not look very pretty
# (as most code dealing with many long strings), but its performance makes it very sexy! ;)
module Frontend
# Generic pagination: it returns the html with the series of links to the pages
def pagy_nav(pagy)
html, link, p_prev, p_next = +'', pagy_link_proc(pagy), pagy.prev, pagy.next
html << (p_prev ? %(#{link.call p_prev, pagy_t('pagy.nav.prev'), 'aria-label="previous"'} )
: %(#{pagy_t('pagy.nav.prev')} ))
pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
html << if item.is_a?(Integer); %(#{link.call item} ) # page link
elsif item.is_a?(String) ; %(#{item} ) # current page
elsif item == :gap ; %(#{pagy_t('pagy.nav.gap')} ) # page gap
end
end
html << (p_next ? %(#{link.call p_next, pagy_t('pagy.nav.next'), 'aria-label="next"'})
: %(#{pagy_t('pagy.nav.next')}))
%()
end
# Return examples: "Displaying items 41-60 of 324 in total" or "Displaying Products 41-60 of 324 in total"
def pagy_info(pagy)
name = pagy_t(pagy.vars[:item_path], count: pagy.count)
path = pagy.pages == 1 ? 'pagy.info.single_page' : 'pagy.info.multiple_pages'
pagy_t(path, item_name: name, count: pagy.count, from: pagy.from, to: pagy.to)
end
# This works with all Rack-based frameworks (Sinatra, Padrino, Rails, ...)
def pagy_url_for(page, pagy)
p_vars = pagy.vars; params = request.GET.merge(p_vars[:page_param].to_s => page).merge!(p_vars[:params])
"#{request.path}?#{Rack::Utils.build_nested_query(pagy_get_params(params))}#{p_vars[:anchor]}"
end
# Sub-method called only by #pagy_url_for: here for easy customization of params by overriding
def pagy_get_params(params) params end
MARKER = "-pagy-#{'pagy'.hash}-"
# Returns a performance optimized proc to generate the HTML links
# Benchmarked on a 20 link nav: it is ~27x faster and uses ~13x less memory than rails' link_to
def pagy_link_proc(pagy, link_extra='')
p_prev, p_next = pagy.prev, pagy.next
a, b = %( (n, text=n, extra='') { "#{a}#{n}#{b}#{ if n == p_prev ; ' rel="prev"'
elsif n == p_next ; ' rel="next"'
else '' end } #{extra}>#{text}" }
end
# Pagy::Frontend::I18N
def (I18N = {data:{}}).load(file:Pagy.root.join('locales', 'pagy.yml'), language: 'en')
self[:data] = YAML.load_file(file)[language]
self[:plural] = eval(Pagy.root.join('locales', 'plurals.rb').read)[language] #rubocop:disable Security/Eval
end; I18N.load
# Similar to I18n.t for streamlined interpolation and pluralization but without dynamic translation.
# It is specialized for Pagy and 5x faster than I18n.t (see https://ddnexus.github.io/pagy/api/frontend#i18n)
# See also https://ddnexus.github.io/pagy/extras/i18n if you need to use the standard I18n gem instead
def pagy_t(path, vars={})
value = I18N[:data].dig(*path.split('.')) or return %(translation missing: "#{path}")
if value.is_a?(Hash)
vars.key?(:count) or return value
plural = I18N[:plural].call(vars[:count])
value.key?(plural) or return %(invalid pluralization data: "#{path}" cannot be used with count: #{vars[:count]}; key "#{plural}" is missing.)
value = value[plural] or return %(translation missing: "#{path}")
end
sprintf value, Hash.new{|_,k| "%{#{k}}"}.merge!(vars) # interpolation
end
end
end