Skip to content

Commit cbd88c6

Browse files
committed
WIP: Better Calendar paginator
1 parent 746d911 commit cbd88c6

File tree

5 files changed

+33
-48
lines changed

5 files changed

+33
-48
lines changed

gem/lib/pagy/backend/paginators/calendar.rb

+4-41
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,14 @@
22

33
class Pagy
44
# Add pagination filtering by calendar unit (:year, :quarter, :month, :week, :day) to the regular pagination
5-
# Additions for the Backend module
6-
module CalendarBackendAddOn
7-
CALENDAR_CONF_KEYS = (Offset::Calendar::UNITS + %i[pagy active]).freeze
8-
5+
Backend.module_eval do
96
private
107

118
# Take a collection and a conf Hash with keys in CONF_KEYS and return an array with 3 items: [calendar, pagy, results]
129
def pagy_calendar(collection, conf)
13-
raise ArgumentError, "keys must be in #{CALENDAR_CONF_KEYS.inspect}" \
14-
unless conf.is_a?(Hash) && (conf.keys - CALENDAR_CONF_KEYS).empty?
10+
conf_keys = Offset::Calendar::UNITS + %i[pagy active]
11+
raise ArgumentError, "keys must be in #{conf_keys.inspect}" \
12+
unless conf.is_a?(Hash) && (conf.keys - conf_keys).empty?
1513

1614
conf[:pagy] ||= {}
1715
unless conf.key?(:active) && !conf[:active]
@@ -36,39 +34,4 @@ def pagy_calendar_filter(*)
3634
'(see https://ddnexus.github.io/pagy/docs/extras/calendar/#pagy-calendar-filter-collection-from-to)'
3735
end
3836
end
39-
Backend.prepend CalendarBackendAddOn
40-
41-
# Override the pagy_anchor
42-
module CalendarFrontendOverride
43-
# Consider the vars[:counts]
44-
def pagy_anchor(pagy, anchor_string: nil, **vars)
45-
return super unless (counts = pagy.vars[:counts])
46-
47-
anchor_string &&= %( #{anchor_string})
48-
left, right = %(<a#{anchor_string} href="#{pagy_page_url(pagy, PAGE_TOKEN, **vars)}").split(PAGE_TOKEN, 2)
49-
# lambda used by all the helpers
50-
lambda do |page, text = pagy.label(page: page), classes: nil, aria_label: nil|
51-
count = counts[page - 1]
52-
if count.zero?
53-
classes = "#{classes && (classes + ' ')}empty-page"
54-
info_key = 'pagy.info.no_items'
55-
else
56-
info_key = 'pagy.info.single_page'
57-
end
58-
title = %( title="#{pagy_t(info_key, item_name: pagy_t('pagy.item_name', count:), count:)}")
59-
classes &&= %( class="#{classes}")
60-
aria_label &&= %( aria-label="#{aria_label}")
61-
%(#{left}#{page}#{right}#{title}#{classes}#{aria_label}>#{text}</a>)
62-
end
63-
end
64-
end
65-
Frontend.prepend CalendarFrontendOverride
66-
67-
# Additions for the Frontend module
68-
Url.module_eval do
69-
# Return the url for the calendar page at time
70-
def pagy_calendar_url_at(calendar, time, **)
71-
pagy_page_url(calendar.send(:calendar_at, time, **), 1, **)
72-
end
73-
end
7437
end

gem/lib/pagy/frontend.rb

+17-3
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,27 @@ module Frontend
1111
# Return a performance optimized lambda to generate the HTML anchor element (a tag)
1212
# Benchmarked on a 20 link nav: it is ~22x faster and uses ~18x less memory than rails' link_to
1313
def pagy_anchor(pagy, anchor_string: nil, **vars)
14+
if (counts = pagy.vars[:calendar_counts]) # only set if pagy_calendar_counts is defined
15+
calendar_augmentation = lambda do |page, classes|
16+
count = counts[page - 1]
17+
if count.zero?
18+
classes = classes ? "#{classes} empty-page" : 'empty-page'
19+
info_key = 'pagy.info.no_items'
20+
else
21+
info_key = 'pagy.info.single_page'
22+
end
23+
title = %( title="#{pagy_t(info_key, item_name: pagy_t('pagy.item_name', count:), count:)}")
24+
[classes, title]
25+
end
26+
end
1427
anchor_string &&= %( #{anchor_string})
1528
left, right = %(<a#{anchor_string} href="#{pagy_page_url(pagy, PAGE_TOKEN, **vars)}").split(PAGE_TOKEN, 2)
1629
# lambda used by all the helpers
1730
lambda do |page, text = pagy.label(page: page), classes: nil, aria_label: nil|
18-
classes &&= %( class="#{classes}")
19-
aria_label &&= %( aria-label="#{aria_label}")
20-
%(#{left}#{page}#{right}#{classes}#{aria_label}>#{text}</a>)
31+
classes, title = calendar_augmentation.(page, classes) if calendar_augmentation
32+
classes &&= %( class="#{classes}")
33+
aria_label &&= %( aria-label="#{aria_label}")
34+
%(#{left}#{page}#{right}#{title}#{classes}#{aria_label}>#{text}</a>)
2135
end
2236
end
2337

gem/lib/pagy/modules/url.rb

+5
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,10 @@ def pagy_page_url(pagy, page, absolute: false, fragment: nil, **)
6262

6363
"#{request.base_url if absolute}#{vars[:request_path] || request.path}#{query_string}#{fragment}"
6464
end
65+
66+
# Return the url for the calendar page at time
67+
def pagy_calendar_url_at(calendar, time, **)
68+
pagy_page_url(calendar.send(:calendar_at, time, **), 1, **)
69+
end
6570
end
6671
end

gem/lib/pagy/offset/calendar.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,10 @@ def init(conf, period, params)
6868
conf[unit][:period] = object&.send(:active_period) || @period
6969
conf[unit][:page] = @params[:"#{unit}_#{@page_sym}"] # requested page
7070
# :nocov:
71-
conf[unit][:counts] = yield(unit, conf[unit][:period]) if block_given? # nocov doesn't need to fail block_given?
71+
# simplecov doesn't need to fail block_given?
72+
conf[unit][:calendar_counts] = yield(unit, conf[unit][:period]) if block_given?
7273
# :nocov:
73-
calendar[unit] = object \
74-
= Calendar.send(:create, unit, **conf[unit])
74+
calendar[unit] = object = Calendar.send(:create, unit, **conf[unit])
7575
end
7676
[replace(calendar), object.from, object.to]
7777
end

test/pagy/offset/overflow_test.rb

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
# frozen_string_literal: true
22

33
require_relative '../../test_helper'
4-
require 'pagy/backend/paginators/calendar' # to avoid to load AR support
4+
5+
# Lazy trick to load ActiveSupport and crap while silencing the warnings
6+
calendar = Pagy::Offset::Calendar
7+
puts calendar
58

69
Time.zone = 'EST'
710
Date.beginning_of_week = :sunday

0 commit comments

Comments
 (0)