Class: Pagy

Inherits:
Object
  • Object
show all
Extended by:
Configurable
Includes:
Linkable, Loader
Defined in:
lib/pagy.rb,
lib/pagy/modules/b64.rb,
lib/pagy/classes/request.rb,
lib/pagy/modules/console.rb,
lib/pagy/modules/searcher.rb,
lib/pagy/modules/i18n/i18n.rb,
lib/pagy/modules/i18n/p11n.rb,
lib/pagy/classes/exceptions.rb,
lib/pagy/classes/calendar/day.rb,
lib/pagy/classes/calendar/unit.rb,
lib/pagy/classes/calendar/week.rb,
lib/pagy/classes/calendar/year.rb,
lib/pagy/classes/keyset/keynav.rb,
lib/pagy/classes/keyset/keyset.rb,
lib/pagy/classes/offset/offset.rb,
lib/pagy/classes/offset/search.rb,
lib/pagy/classes/calendar/month.rb,
lib/pagy/toolbox/helpers/loader.rb,
lib/pagy/classes/offset/countish.rb,
lib/pagy/modules/i18n/p11n/other.rb,
lib/pagy/classes/calendar/quarter.rb,
lib/pagy/classes/offset/countless.rb,
lib/pagy/modules/i18n/p11n/arabic.rb,
lib/pagy/modules/i18n/p11n/polish.rb,
lib/pagy/toolbox/helpers/info_tag.rb,
lib/pagy/toolbox/helpers/page_url.rb,
lib/pagy/classes/calendar/calendar.rb,
lib/pagy/toolbox/helpers/data_hash.rb,
lib/pagy/toolbox/helpers/urls_hash.rb,
lib/pagy/toolbox/paginators/keyset.rb,
lib/pagy/toolbox/paginators/method.rb,
lib/pagy/toolbox/paginators/offset.rb,
lib/pagy/modules/abilities/linkable.rb,
lib/pagy/toolbox/helpers/series_nav.rb,
lib/pagy/modules/abilities/countable.rb,
lib/pagy/modules/abilities/rangeable.rb,
lib/pagy/modules/abilities/shiftable.rb,
lib/pagy/modules/i18n/p11n/one_other.rb,
lib/pagy/toolbox/helpers/anchor_tags.rb,
lib/pagy/toolbox/paginators/calendar.rb,
lib/pagy/toolbox/paginators/countish.rb,
lib/pagy/toolbox/helpers/headers_hash.rb,
lib/pagy/toolbox/helpers/input_nav_js.rb,
lib/pagy/toolbox/helpers/limit_tag_js.rb,
lib/pagy/toolbox/paginators/countless.rb,
lib/pagy/toolbox/paginators/keynav_js.rb,
lib/pagy/modules/i18n/p11n/east_slavic.rb,
lib/pagy/modules/i18n/p11n/west_slavic.rb,
lib/pagy/toolbox/helpers/series_nav_js.rb,
lib/pagy/toolbox/paginators/searchkick.rb,
lib/pagy/classes/keyset/adapters/sequel.rb,
lib/pagy/modules/abilities/configurable.rb,
lib/pagy/toolbox/helpers/support/series.rb,
lib/pagy/toolbox/paginators/meilisearch.rb,
lib/pagy/toolbox/helpers/bulma/series_nav.rb,
lib/pagy/toolbox/helpers/support/a_lambda.rb,
lib/pagy/toolbox/helpers/bulma/input_nav_js.rb,
lib/pagy/toolbox/helpers/bulma/series_nav_js.rb,
lib/pagy/modules/i18n/p11n/one_upto_two_other.rb,
lib/pagy/toolbox/helpers/bootstrap/series_nav.rb,
lib/pagy/classes/keyset/adapters/active_record.rb,
lib/pagy/toolbox/helpers/bootstrap/input_nav_js.rb,
lib/pagy/toolbox/paginators/elasticsearch_rails.rb,
lib/pagy/toolbox/helpers/bootstrap/series_nav_js.rb,
lib/pagy/toolbox/helpers/support/wrap_series_nav.rb,
lib/pagy/toolbox/helpers/bulma/previous_next_html.rb,
lib/pagy/toolbox/helpers/support/wrap_input_nav_js.rb,
lib/pagy/toolbox/helpers/support/wrap_series_nav_js.rb,
lib/pagy/toolbox/helpers/support/data_pagy_attribute.rb,
lib/pagy/toolbox/helpers/bootstrap/previous_next_html.rb,
lib/pagy/toolbox/helpers/support/nav_aria_label_attribute.rb

Overview

Relegate internal functions. Make overriding navs easier.

Direct Known Subclasses

Calendar::Unit, Keyset, Offset

Defined Under Namespace

Modules: B64, CalendarPaginator, Configurable, Console, Countable, CountishPaginator, CountlessPaginator, ElasticsearchRailsPaginator, I18n, KeynavJsPaginator, KeysetPaginator, Linkable, Loader, MeilisearchPaginator, OffsetPaginator, Rangeable, Search, Searcher, SearchkickPaginator, Shiftable Classes: Calendar, ElasticsearchRails, EscapedValue, InternalError, Keyset, Meilisearch, Offset, OptionError, RailsI18nLoadError, RangeError, Request, SearchBase, Searchkick

Constant Summary collapse

VERSION =
'43.2.1'
ROOT =
Pathname.new(__dir__).parent.freeze
DEFAULT =
{ limit: 20, limit_key: 'limit', page_key: 'page' }.freeze
PAGE_TOKEN =
EscapedValue.new('P ')
LIMIT_TOKEN =
EscapedValue.new('L ')
LABEL_TOKEN =
'L'
A_TAG =
'<a style="display: none;">#</a>'
DEFAULT_DATA_KEYS =
i[url_template first_url previous_url current_url page_url next_url last_url
count page limit last in from to previous next options].freeze
Method =

Pagy::Method defines the #pagy method to be included in the app controller/view.

Module.new do
  protected

  define_method :pagy do |paginator = :offset, collection, **options|
    arguments           = if paginator == :calendar
                            [self, collection, options]
                          else
                            [collection, options = Pagy.options.merge(options)]
                          end
    options[:root_key]  = 'page' if options[:jsonapi] # enforce 'page' root_key for JSON:API
    options[:request] ||= request                     # user set request or self.request
    options[:request]   = Request.new(options)        # Pagy::Request
    Pagy.const_get(paginators[paginator]).paginate(*arguments)
  end
end
DEFAULT_HEADERS_MAP =
{ page: 'current-page',
limit: 'page-limit',
count: 'total-count',
pages: 'total-pages' }.freeze
SERIES_SLOTS =
7

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Configurable

dev_tools, sync_javascript, translate_with_the_slower_i18n_gem!

Instance Attribute Details

#inObject (readonly)

Returns the value of attribute in.



37
38
39
# File 'lib/pagy.rb', line 37

def in
  @in
end

#limitObject (readonly)

Returns the value of attribute limit.



37
38
39
# File 'lib/pagy.rb', line 37

def limit
  @limit
end

#nextObject (readonly)

Returns the value of attribute next.



37
38
39
# File 'lib/pagy.rb', line 37

def next
  @next
end

#optionsObject (readonly)

Returns the value of attribute options.



37
38
39
# File 'lib/pagy.rb', line 37

def options
  @options
end

#pageObject (readonly)

Returns the value of attribute page.



37
38
39
# File 'lib/pagy.rb', line 37

def page
  @page
end

Class Method Details

.optionsObject



31
# File 'lib/pagy.rb', line 31

def self.options = @options ||= {}

Instance Method Details

#data_hash(data_keys: @options[:data_keys] || DEFAULT_DATA_KEYS) ⇒ Object

Generate a hash of the wanted internal data



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/pagy/toolbox/helpers/data_hash.rb', line 8

def data_hash(data_keys: @options[:data_keys] || DEFAULT_DATA_KEYS, **)
  template   = compose_page_url(PAGE_TOKEN, **)
  to_url     = ->(page) { template.sub(PAGE_TOKEN, page.to_s) if page }
  data_keys -= i[count limit] if calendar?
  data_keys.each_with_object({}) do |key, data|
    value = case key
            when :url_template           then template
            when :first_url              then compose_page_url(nil, **)
            when :previous_url           then to_url.(@previous)
            when :current_url, :page_url then to_url.(@page)
            when :next_url               then to_url.(@next)
            when :last_url               then to_url.(@last)
            else send(key)
            end
    data[key] = value if value
  rescue NoMethodError
    raise OptionError.new(self, :data_keys, 'to contain known keys/methods', key)
  end
end

#headers_hash(headers_map: @options[:headers_map] || DEFAULT_HEADERS_MAP) ⇒ Object

Generate a hash of RFC-8288-compliant http headers



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/pagy/toolbox/helpers/headers_hash.rb', line 13

def headers_hash(headers_map: @options[:headers_map] || DEFAULT_HEADERS_MAP, **)
  links = urls_hash(**, absolute: true).map { %(<#{_2}>; rel="#{_1}") }.join(', ')
  headers_map.each_with_object('link' => links) do |(key, name), hash|
    next unless name

    # :nocov:
    value = case key
            when :page  then @page
            when :limit then @limit unless calendar?
            when :pages then @last  if @count
            when :count then @count
            end
    # :nocov:
    hash[name] = value.to_s if value
  end
end

#info_tag(id: nil, item_name: nil) ⇒ Object

Instances with count return “Displaying items 41-60 of 324 in total” or “Displaying Products 41-60 of 324 in total” Instances with no count return only page info: “Page 3 of 100”



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/pagy/toolbox/helpers/info_tag.rb', line 6

def info_tag(id: nil, item_name: nil)
  i18n_key  = if @count.nil?
                'pagy.info_tag.no_count'
              elsif @count.zero?
                'pagy.info_tag.no_items'
              elsif @in == @count
                'pagy.info_tag.single_page'
              else
                'pagy.info_tag.multiple_pages'
              end
  info_data = if @count.nil?
                { page: @page, pages: @last }
              else
                { item_name: item_name || I18n.translate('pagy.item_name', count: @count),
                  count:     @count,
                  from:      @from,
                  to:        @to }
              end
  %(<span#{%( id="#{id}") if id} class="pagy info">#{I18n.translate(i18n_key, **info_data)}</span>)
end

#input_nav_js(style = nil) ⇒ Object

JavaScript input pagination: it returns a nav with a data-pagy attribute used by the pagy.js file



7
8
9
10
11
12
13
14
15
16
17
# File 'lib/pagy/toolbox/helpers/input_nav_js.rb', line 7

def input_nav_js(style = nil, **)
  return send(:"#{style}_input_nav_js", **) if style

  a_lambda = a_lambda(**)
  input    = %(<input name="page" type="number" min="1" max="#{@last}" value="#{@page}" aria-current="page" ) +
             %(style="text-align: center; width: #{@page.to_s.length + 1}rem; padding: 0;">#{A_TAG})
  html     = %(#{previous_tag(a_lambda)}<label>#{
               I18n.translate('pagy.input_nav_js', page_input: input, pages: @last)}</label>#{
               next_tag(a_lambda)})
  wrap_input_nav_js(html, 'pagy input-nav-js', **)
end

#limit_tag_js(id: nil, item_name: nil, client_max_limit: @options[:client_max_limit]) ⇒ Object

Return the limit selector HTML. For example “Show [20] items per page”

Raises:



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/pagy/toolbox/helpers/limit_tag_js.rb', line 7

def limit_tag_js(id: nil, item_name: nil, client_max_limit: @options[:client_max_limit], **)
  raise OptionError.new(self, :client_max_limit, 'to be truthy', client_max_limit) unless client_max_limit

  limit_input = %(<input name="limit" type="number" min="1" max="#{client_max_limit}" value="#{
                  @limit}" style="padding: 0; text-align: center; width: #{@limit.to_s.length + 1}rem;">#{A_TAG})
  url_token   = compose_page_url(PAGE_TOKEN, limit: LIMIT_TOKEN)

  %(<span#{%( id="#{id}") if id} class="pagy limit-tag-js" #{
    data_pagy_attribute(:ltj, @from, url_token, PAGE_TOKEN, LIMIT_TOKEN)
    }><label>#{
    I18n.translate('pagy.limit_tag_js',
                   item_name: item_name || I18n.translate('pagy.item_name', count: @limit),
                   limit_input:,
                   count: @limit)
    }</label></span>)
end

#next_tag(a = nil, text: I18n.translate('pagy.next'), aria_label: I18n.translate('pagy.aria_label.next')) ⇒ Object

Return the enabled/disabled next page anchor tag



17
18
19
20
21
22
23
24
# File 'lib/pagy/toolbox/helpers/anchor_tags.rb', line 17

def next_tag(a = nil, text: I18n.translate('pagy.next'),
             aria_label: I18n.translate('pagy.aria_label.next'), **)
  if @next
    (a || a_lambda(**)).(@next, text, aria_label:)
  else
    %(<a role="link" aria-disabled="true" aria-label="#{aria_label}">#{text}</a>)
  end
end

#page_url(page) ⇒ Object

Return the page url for any page



5
6
7
8
9
10
11
12
13
14
15
# File 'lib/pagy/toolbox/helpers/page_url.rb', line 5

def page_url(page, **)
  target = case page
           when :first          then nil
           when :current, :page then @page
           when :previous       then @previous
           when :next           then @next
           when :last           then @last
           else                      page
           end
  compose_page_url(target, **) if target || page == :first
end

#previous_tag(a = nil, text: I18n.translate('pagy.previous'), aria_label: I18n.translate('pagy.aria_label.previous')) ⇒ Object

Return the enabled/disabled previous page anchor tag



7
8
9
10
11
12
13
14
# File 'lib/pagy/toolbox/helpers/anchor_tags.rb', line 7

def previous_tag(a = nil, text: I18n.translate('pagy.previous'),
                 aria_label: I18n.translate('pagy.aria_label.previous'), **)
  if @previous
    (a || a_lambda(**)).(@previous, text, aria_label:)
  else
    %(<a role="link" aria-disabled="true" aria-label="#{aria_label}">#{text}</a>)
  end
end

#series_nav(style = nil) ⇒ Object

Return the HTML with the series of links to the pages



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/pagy/toolbox/helpers/series_nav.rb', line 7

def series_nav(style = nil, **)
  return send(:"#{style}_series_nav", **) if style

  a_lambda = a_lambda(**)
  html     = previous_tag(a_lambda)
  series(**).each do |item|
    # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
    html << case item
            when Integer
              a_lambda.(item)
            when String
              %(<a role="link" aria-disabled="true" aria-current="page">#{page_label(item)}</a>)
            when :gap
              %(<a role="separator" aria-disabled="true">#{I18n.translate('pagy.gap')}</a>)
            else
              raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
            end
  end
  html << next_tag(a_lambda)
  wrap_series_nav(html, 'pagy series-nav', **)
end

#series_nav_js(style = nil) ⇒ Object

Return a nav with a data-pagy attribute used by the pagy.js file



7
8
9
10
11
12
13
14
15
16
17
# File 'lib/pagy/toolbox/helpers/series_nav_js.rb', line 7

def series_nav_js(style = nil, **)
  return send(:"#{style}_series_nav_js", **) if style

  a_lambda = a_lambda(**)
  tokens   = { before:  previous_tag(a_lambda),
               anchor:  a_lambda.(PAGE_TOKEN, LABEL_TOKEN),
               current: %(<a role="link" aria-current="page" aria-disabled="true">#{LABEL_TOKEN}</a>),
               gap:     %(<a role="separator" aria-disabled="true">#{I18n.translate('pagy.gap')}</a>),
               after:   next_tag(a_lambda) }
  wrap_series_nav_js(tokens, 'pagy series-nav-js', **)
end

#urls_hashObject

Generate the hash of the pagination links



5
6
7
8
9
10
11
12
# File 'lib/pagy/toolbox/helpers/urls_hash.rb', line 5

def urls_hash(**)
  template = compose_page_url(PAGE_TOKEN, **)

  { first:    compose_page_url(nil, **),
    previous: @previous && template.sub(PAGE_TOKEN, @previous.to_s),
    next:     @next     && template.sub(PAGE_TOKEN, @next.to_s),
    last:     @count    && template.sub(PAGE_TOKEN, @last.to_s) }.compact
end