Skip to content

Commit

Permalink
Add aria-label to nav (closes #611):
Browse files Browse the repository at this point in the history
- Revise aria attributed
- Refactor support helpers
  - pagy_prev_link -> pagy_prev_html without optional text argument
  - pagy_next_link -> pagy_next_html without optional text argument
  • Loading branch information
ddnexus committed Jan 21, 2024
1 parent 4e90666 commit 00bfe64
Show file tree
Hide file tree
Showing 15 changed files with 333 additions and 320 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ None

- Dropped old rubies support: Pagy follows the [ruby end-of-life](https://endoflife.date/ruby) supported rubies now.
- Renamed `:i18n_key` > `:item_i18n_key`
- Refactored `support` extra
- Removed `pagy_prev_link`: use `pagy_prev_html` without the `:text` argument (can customize `pagy.nav.prev`)
- Removed `pagy_next_link`: use `pagy_next_html` without the `:text` argument (can customize `pagy.nav.next`)

### Default changes possibly breaking test/views

Expand Down
2 changes: 1 addition & 1 deletion apps/pagy_standalone_app.ru
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ require 'bundler/inline'
# NOTICE: if you get any installation error with the following setup
# temporarily remove the Gemfile and Gemfile.lock from the repo (they may interfere with the bundler/inline)

gemfile true do
gemfile false do
source 'https://rubygems.org'
gem 'oj'
gem 'rack'
Expand Down
19 changes: 11 additions & 8 deletions docs/extras/support.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ You can totally avoid one query per render by using the [countless](countless.md

If you don't need the navbar you can just set the `:size` variable to an empty value and the page links will be skipped from the rendering. That works with `Pagy` and `Pagy:Countless` instances. All the `*nav` helpers will render only the `prev` and `next` links/buttons, allowing for a manual incremental pagination.

You can also use the [`pagy_prev_link`](https://github.com/ddnexus/pagy/blob/dca8669a10cb3be13e053fe435301c22cc64406f/lib/pagy/extras/navs.rb#L46) and [`pagy_next_link`](https://github.com/ddnexus/pagy/blob/dca8669a10cb3be13e053fe435301c22cc64406f/lib/pagy/extras/navs.rb#L54) helpers provided by the [navs extra](navs), mostly useful if you also use the `countless` extra.
You can also use the [`pagy_prev_html`](https://github.com/ddnexus/pagy/blob/dca8669a10cb3be13e053fe435301c22cc64406f/lib/pagy/extras/navs.rb#L46) and [`pagy_next_html`](https://github.com/ddnexus/pagy/blob/dca8669a10cb3be13e053fe435301c22cc64406f/lib/pagy/extras/navs.rb#L54) helpers provided by the [navs extra](navs), mostly useful if you also use the `countless` extra.

Here is a basic example that uses `pagy_countless` (saving one query per render):

Expand Down Expand Up @@ -77,7 +77,7 @@ end

||| _next_link.html.erb (partial)
```erb
<%== pagy_next_link(@pagy, text: 'More...', link_extra: 'id="next_link"') %>
<%== pagy_next_html(@pagy, text: 'More...', link_extra: 'id="next_link"') %>
```
|||

Expand All @@ -103,7 +103,7 @@ For a plain old javascript example, we are going to use the same [Incremental](#

||| _next_link.html.erb (partial)
```erb
<%== pagy_next_link(@pagy, text: 'More...', link_extra: 'id="next_link" style="display: none;"') %>
<%== pagy_next_html(@pagy, text: 'More...', link_extra: 'id="next_link" style="display: none;"') %>
```
|||

Expand Down Expand Up @@ -147,7 +147,7 @@ You may want to combine it with something like:

||| View
```erb
<%== pagy_next_link(@pagy, text: 'More...') %>
<%== pagy_next_html(@pagy, text: 'More...') %>
```
|||

Expand All @@ -161,15 +161,18 @@ Returns the url for the previous page. Useful to build minimalistic UIs that don

Returns the url for the next page. Useful to build minimalistic UIs that don't use nav bar links (e.g. `countless` extra).

==- `pagy_prev_link(pagy, text: pagy_t('pagy.nav.prev'), link_extra: "")`
==- `pagy_prev_html(pagy, link_extra: "")`

Returns the `a` tag for the previous page. It is the same prev link string which is part of the `pagy_nav` helper.
Returns the enabled/disabled HTML string for the previous page link. It is the same prev link string which is
part of the
`pagy_nav` helper.

Useful to build minimalistic helpers UIs that don't use nav bar links (e.g. `countless` extra).

==- `pagy_next_link(pagy, text: pagy_t('pagy.nav.next'), link_extra: "")`
==- `pagy_next_html(pagy, link_extra: "")`

Returns the `a` tag for the next page. It is the same next link string which is part of the `pagy_nav` helper.
Returns the enabled/disabled HTML string for the next page link. It is the same next link string which is part of the
`pagy_nav` helper.

Useful to build minimalistic helpers UIs that don't use nav bar links (e.g. `countless` extra).

Expand Down
1 change: 1 addition & 0 deletions lib/pagy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def self.root
fragment: '',
link_extra: '',
item_i18n_key: 'pagy.item_name',
page_i18n_key: 'pagy.page_label',
cycle: false,
request_path: '' }

Expand Down
13 changes: 7 additions & 6 deletions lib/pagy/extras/frontend_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class Pagy # :nodoc:
# Private module documented in the main classes
module FrontendHelpers
# Additions for the Pagy class
module Pagy
module PagyOverride
# `Pagy` instance method used by the `pagy*_nav_js` helpers.
# It returns the sequels of width/series generated from the :steps hash
# Example:
Expand All @@ -26,10 +26,12 @@ def sequels(steps: @vars[:steps] || { 0 => @vars[:size] }, **_)

# Support for the Calendar API
def label_sequels(*); end

end
Pagy.prepend PagyOverride

# Additions for Calendar class
module Calendar
module CalendarOverride
def label_sequels(sequels = self.sequels)
{}.tap do |label_sequels|
sequels.each do |width, series|
Expand All @@ -38,9 +40,10 @@ def label_sequels(sequels = self.sequels)
end
end
end
Calendar.prepend CalendarOverride if defined?(Calendar)

# Additions for the Frontend
module Frontend
module FrontendOverride
if defined?(Oj)
# Return a data tag with the base64 encoded JSON-serialized args generated with the faster oj gem
# Base64 encoded JSON is smaller than HTML escaped JSON
Expand All @@ -65,8 +68,6 @@ def pagy_marked_link(link)
link.call PAGE_PLACEHOLDER, '', 'style="display: none;"'
end
end
Frontend.prepend FrontendOverride
end
prepend FrontendHelpers::Pagy
Calendar.prepend FrontendHelpers::Calendar if defined?(Calendar)
Frontend.prepend FrontendHelpers::Frontend
end
43 changes: 15 additions & 28 deletions lib/pagy/extras/navs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,56 +8,43 @@ class Pagy # :nodoc:
# The resulting code may not look very elegant, but produces the best benchmarks
module NavsExtra
# Javascript pagination: it returns a nav and a JSON tag used by the pagy.js file
def pagy_nav_js(pagy, pagy_id: nil, link_extra: '', **vars)
def pagy_nav_js(pagy, pagy_id: nil, link_extra: '',
page_label: nil, page_i18n_key: nil, **vars)
sequels = pagy.sequels(**vars)
p_id = %( id="#{pagy_id}") if pagy_id
link = pagy_link_proc(pagy, link_extra:)
tags = { 'before' => pagy_nav_prev_html(pagy, link),
'link' => %(<span class="page">#{link.call(PAGE_PLACEHOLDER, LABEL_PLACEHOLDER)}</span> ),
'active' => %(<span class="page active">#{LABEL_PLACEHOLDER}</span> ),
'active' => %(<span class="page active">) +
%(<a role="link" aria-disabled="true" aria-current="page">#{LABEL_PLACEHOLDER}</a></span> ),
'gap' => %(<span class="page gap">#{pagy_t 'pagy.nav.gap'}</span> ),
'after' => pagy_nav_next_html(pagy, link) }

%(<nav#{p_id} class="#{'pagy-rjs ' if sequels.size > 1}pagy-nav-js pagination" #{
pagy_data(pagy, :nav, tags, sequels, pagy.label_sequels(sequels))}></nav>)
pagy_aria_label(pagy, page_label, page_i18n_key)} #{
pagy_data(pagy, :nav, tags, sequels, pagy.label_sequels(sequels))
}></nav>)
end

# Javascript combo pagination: it returns a nav and a JSON tag used by the pagy.js file
def pagy_combo_nav_js(pagy, pagy_id: nil, link_extra: '')
def pagy_combo_nav_js(pagy, pagy_id: nil, link_extra: '',
page_label: nil, page_i18n_key: nil)
p_id = %( id="#{pagy_id}") if pagy_id
link = pagy_link_proc(pagy, link_extra:)
p_page = pagy.page
p_pages = pagy.pages
input = %(<input type="number" min="1" max="#{p_pages}" value="#{
p_page}" style="padding: 0; text-align: center; width: #{p_pages.to_s.length + 1}rem;">)
input = %(<input type="number" min="1" max="#{p_pages}" value="#{p_page}" ) +
%(style="padding: 0; text-align: center; width: #{p_pages.to_s.length + 1}rem;">)

%(<nav#{p_id} class="pagy-combo-nav-js pagination" #{
pagy_data(pagy, :combo, pagy_marked_link(link))}>#{
pagy_nav_prev_html pagy, link
pagy_aria_label(pagy, page_label, page_i18n_key)} #{
pagy_data(pagy, :combo, pagy_marked_link(link))}>#{pagy_nav_prev_html(pagy, link)
}<span class="pagy-combo-input" style="margin: 0 0.6rem;">#{
pagy_t 'pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages
pagy_t('pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages)
}</span> #{
pagy_nav_next_html pagy, link
pagy_nav_next_html(pagy, link)
}</nav>)
end

private

def pagy_nav_prev_html(pagy, link)
if (p_prev = pagy.prev)
%(<span class="page prev">#{link.call p_prev, pagy_t('pagy.nav.prev'), 'aria-label="previous"'}</span> )
else
%(<span class="page prev disabled">#{pagy_t 'pagy.nav.prev'}</span> )
end
end

def pagy_nav_next_html(pagy, link)
if (p_next = pagy.next)
%(<span class="page next">#{link.call p_next, pagy_t('pagy.nav.next'), 'aria-label="next"'}</span>)
else
%(<span class="page next disabled">#{pagy_t 'pagy.nav.next'}</span>)
end
end
end
Frontend.prepend NavsExtra
end
34 changes: 10 additions & 24 deletions lib/pagy/extras/support.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,38 +14,24 @@ def pagy_next_url(pagy)
pagy_url_for(pagy, pagy.next) if pagy.next
end

# Return the HTML string for the previous page link
def pagy_prev_link(pagy, text: pagy_t('pagy.nav.prev'), link_extra: '')
if pagy.prev
%(<span class="page prev"><a href="#{
pagy_url_for(pagy, pagy.prev, html_escaped: true)
}" rel="prev" aria-label="previous" #{
pagy.vars[:link_extra]
} #{link_extra}>#{text}</a></span>)
else
%(<span class="page prev disabled">#{text}</span>)
end
# Return the enabled/disabled HTML string for the previous page link
def pagy_prev_html(pagy, link_extra: '', **vars)
link = pagy_link_proc(pagy, link_extra:)
pagy_nav_prev_html(pagy, link)
end

# Return the HTML string for the next page link
def pagy_next_link(pagy, text: pagy_t('pagy.nav.next'), link_extra: '')
if pagy.next
%(<span class="page next"><a href="#{
pagy_url_for(pagy, pagy.next, html_escaped: true)
}" rel="next" aria-label="next" #{
pagy.vars[:link_extra]
} #{link_extra}>#{text}</a></span>)
else
%(<span class="page next disabled">#{text}</span>)
end
# Return the enabled/disabled HTML string for the next page link
def pagy_next_html(pagy, link_extra: '')
link = pagy_link_proc(pagy, link_extra:)
pagy_nav_next_html(pagy, link)
end

# Return the HTML link tag for the previous page or nil
# Conditionally return the HTML link tag string for the previous page
def pagy_prev_link_tag(pagy)
%(<link href="#{pagy_url_for(pagy, pagy.prev, html_escaped: true)}" rel="prev"/>) if pagy.prev
end

# Return the HTML link tag for the next page or nil
# Conditionally return the HTML link tag string for the next page
def pagy_next_link_tag(pagy)
%(<link href="#{pagy_url_for(pagy, pagy.next, html_escaped: true)}" rel="next"/>) if pagy.next
end
Expand Down
61 changes: 40 additions & 21 deletions lib/pagy/frontend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,27 @@ module Frontend
include UrlHelpers

# Generic pagination: it returns the html with the series of links to the pages
def pagy_nav(pagy, pagy_id: nil, link_extra: '', **vars)
p_id = %( id="#{pagy_id}") if pagy_id
link = pagy_link_proc(pagy, link_extra:)
p_prev = pagy.prev
p_next = pagy.next
def pagy_nav(pagy, pagy_id: nil, link_extra: '',
page_label: nil, page_i18n_key: nil, **vars)
p_id = %( id="#{pagy_id}") if pagy_id
link = pagy_link_proc(pagy, link_extra:)

html = +%(<nav#{p_id} class="pagy-nav pagination">)
html << if p_prev
%(<span class="page prev">#{link.call p_prev, pagy_t('pagy.nav.prev'), 'aria-label="previous"'}</span> )
else
%(<span class="page prev disabled">#{pagy_t('pagy.nav.prev')}</span> )
end
html = +%(<nav#{p_id} class="pagy-nav pagination" #{pagy_aria_label(pagy, page_label, page_i18n_key)}>)
html << pagy_nav_prev_html(pagy, link)
pagy.series(**vars).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
html << case item
when Integer then %(<span class="page">#{link.call item}</span> )
when String then %(<span class="page active">#{pagy.label_for(item)}</span> )
when :gap then %(<span class="page gap">#{pagy_t('pagy.nav.gap')}</span> )
else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
when Integer
%(<span class="page">#{link.call(item)}</span> )
when String
%(<span class="page active">) +
%(<a role="link" aria-disabled="true" aria-current="page">#{pagy.label_for(item)}</a></span> )
when :gap
%(<span class="page gap">#{pagy_t('pagy.nav.gap')}</span> )
else
raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
end
end
html << if p_next
%(<span class="page next">#{link.call p_next, pagy_t('pagy.nav.next'), 'aria-label="next"'}</span>)
else
%(<span class="page next disabled">#{pagy_t('pagy.nav.next')}</span>)
end
html << %(</nav>)
html << %(#{pagy_nav_next_html(pagy, link)}</nav>)
end

# Return examples: "Displaying items 41-60 of 324 in total" or "Displaying Products 41-60 of 324 in total"
Expand Down Expand Up @@ -79,5 +74,29 @@ def pagy_link_proc(pagy, link_extra: '')
def pagy_t(key, opts = {})
Pagy::I18n.translate(@pagy_locale ||= nil, key, opts)
end

# Return the translated aria label
def pagy_aria_label(pagy, page_label, page_i18n_key, count: pagy.pages)
page_label ||= pagy_t(page_i18n_key || pagy.vars[:page_i18n_key], count: count)
%(aria-label="#{page_label}")
end

private

def pagy_nav_prev_html(pagy, link)
if (p_prev = pagy.prev)
%(<span class="page prev">#{link.call p_prev, pagy_t('pagy.nav.prev')}</span> )
else
%(<span class="page prev disabled"><a role="link" aria-disabled="true" rel="prev">#{pagy_t 'pagy.nav.prev'}</a></span> )
end
end

def pagy_nav_next_html(pagy, link)
if (p_next = pagy.next)
%(<span class="page next">#{link.call p_next, pagy_t('pagy.nav.next')}</span>)
else
%(<span class="page next disabled"><a role="link" aria-disabled="true" rel="next">#{pagy_t 'pagy.nav.next'}</a></span>)
end
end
end
end
Loading

0 comments on commit 00bfe64

Please sign in to comment.