Skip to content

Commit

Permalink
Add :leap feature to the calendar units and change the event data
Browse files Browse the repository at this point in the history
  • Loading branch information
ddnexus committed Oct 22, 2024
1 parent 2d41469 commit 7f8a832
Show file tree
Hide file tree
Showing 12 changed files with 493 additions and 471 deletions.
5 changes: 3 additions & 2 deletions docs/api/calendar/units.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ The following variables are specific to `Pagy::Calendar::*` instances:

| Variable | Description | Default |
|:----------|:----------------------------------------------------------------------------------------------------------|:--------|
| `:period` | Required two items Array with the calendar starting and ending local `TimeWithZone` objects | `nil` |
| `:order` | Order of pagination: it can be`:asc` or `:desc` | `:asc` |
| `:format` | String containing the `strftime` extendable format used for labelling (each subclass has its own default) | |
| `:order` | Order of pagination: it can be`:asc` or `:desc` | `:asc` |
| `:period` | Required two items Array with the calendar starting and ending local `TimeWithZone` objects | `nil` |
| `:leap` | Boolean variable to leap empty pages when `pagy_calendar_count` is defined by the app | `nil` |

**Notice**: For the `Pagy::Calendar::Quarter` the `:format` variable can contain a non-standard `%q` format which is substituted
with the quarter (1-4).
Expand Down
24 changes: 18 additions & 6 deletions docs/extras/calendar.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,13 +270,10 @@ So in order to filter the actual search with the `from` and `to` local `TimeWith
==- `pagy_calendar_counts(collection, unit, from, to)`

!!!primary Optional implementation
This method can be implemented by the application in order to add some UI feedback to the pagy nav links
This method can be implemented by the application in order to add some extra UI feedback to the pagy nav links and optionally
leap the empty pages
!!!

If this method is defined, pagy will run it for each used calendar unit and will add an extra `empty-page`
CSS class to the links to empty pages (that can be targeted to give a visual UI feedback). Pagy will also add a `title`
attribute to display a tooltip info for each page link.

The method receives the main `collection`, the `unit` symbol, and must return the array of the counts grouped by unit using the
`from` and `to` **local Time** objects.

Expand All @@ -301,6 +298,21 @@ it on your actual DB in order to evaluate the performance.
If you want to use it dynamically, you can skip the extra query and the relative feedback by returning `nil` when you need it.
!!!

### UI features

If this method is defined, pagy will run it for each configured calendar unit and will add an extra `empty-page`
CSS class to the links to empty pages (that can be targeted to give a visual UI feedback or hide the empty pages). Pagy will also
add a `title` attribute to display a tooltip info for each page link.

You can also leap the empty pages, forcing the UI to land on the next page with results, regardless of the request. Just pass the
`leap: true` variable to the configuration of any unit to enable the behavior for that unit.

!!! Browser address
Notice that the leap feature **does not perform a new request** to the next page with results: it just serves the target page
as it were requested originally. That means that while the UI leaps to the next page with results, the address in the browser
will obviously not update.
!!!

===

## Customization
Expand Down Expand Up @@ -356,7 +368,7 @@ option `fit_time: true` to avoid the error and get the url to the page closest t

Each page link in the calendar navs is conveniently labeled with the specific `Time` period it refers to. You can change the time
format to your needs by setting the `:format` variable to a standard `strftime` format. (See
the [Pagy::Calendar variables](/docs/api/calendar.md#variables))
the [Pagy::Calendar::Unit variables](/docs/api/calendar/units.md#variables))

You can also get the [label method](/docs/api/calendar.md#methods) with e.g.: `@calendar[:month].label`, which might be useful to
use in your UI.
Expand Down
42 changes: 21 additions & 21 deletions e2e/snapshots.js

Large diffs are not rendered by default.

22 changes: 2 additions & 20 deletions gem/apps/calendar.ru
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ class EventsController < ActionController::Base
# which would be inactive by default and only active on demand.
@calendar, @pagy, @events = pagy_calendar(Event.all,
year: {},
month: {},
day: {},
month: { leap: true },
day: { leap: true },
active: !params[:skip])
render inline: TEMPLATE
end
Expand Down Expand Up @@ -278,24 +278,6 @@ TIMES = <<~TIMES
2021-12-27 12:18:57 +0000
2021-12-28 16:59:57 +0000
2021-12-31 15:10:23 +0000
2022-01-01 19:18:06 +0000
2022-01-03 08:36:27 +0000
2022-01-03 23:31:01 +0000
2022-01-05 02:14:57 +0000
2022-01-06 09:26:03 +0000
2022-01-07 20:22:22 +0000
2022-01-10 04:04:28 +0000
2022-01-11 17:17:55 +0000
2022-01-14 05:21:54 +0000
2022-01-16 01:18:58 +0000
2022-01-18 08:42:56 +0000
2022-01-19 00:45:04 +0000
2022-01-20 08:18:54 +0000
2022-01-22 05:26:38 +0000
2022-01-24 10:57:50 +0000
2022-01-26 09:47:02 +0000
2022-01-28 20:44:30 +0000
2022-01-31 16:19:50 +0000
2022-02-01 21:23:58 +0000
2022-02-04 14:41:57 +0000
2022-02-06 20:40:06 +0000
Expand Down
26 changes: 16 additions & 10 deletions gem/lib/pagy/calendar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ def create(unit, **vars)
end

# Return calendar, from, to
def init(conf, period, params)
new.send(:init, conf, period, params)
def init(*args)
new.send(:init, *args)
end
end

Expand All @@ -39,26 +39,32 @@ def showtime
private

# Create the calendar
def init(conf, period, params)
def init(conf, period, params, get_counts)
@conf = Marshal.load(Marshal.dump(conf)) # store a copy
@units = Calendar::UNITS & @conf.keys # get the units in time length desc order
raise ArgumentError, 'no calendar unit found in pagy_calendar @configuration' if @units.empty?

@period = period
@params = params
@page_param = conf[:pagy][:page_param] || DEFAULT[:page_param]
@units.each do |unit| # set all the :page_param vars for later deletion
unit_page_param = :"#{unit}_#{@page_param}"
conf[unit][:page_param] = unit_page_param
conf[unit][:page] = @params[unit_page_param]
end
# set all the :page_param vars for later deletion
@units.each { |unit| conf[unit][:page_param] = :"#{unit}_#{@page_param}" }
calendar = {}
object = nil
@units.each_with_index do |unit, index|
params_to_delete = @units[(index + 1), @units.size].map { |sub| conf[sub][:page_param] } + [@page_param]
conf[unit][:params] = lambda { |up| up.except(*params_to_delete.map(&:to_s)) } # rubocop:disable Style/Lambda
conf[unit][:params] = ->(up) { up.except(*params_to_delete.map(&:to_s)) }
conf[unit][:period] = object&.send(:active_period) || @period
calendar[unit] = object = Calendar.send(:create, unit, **conf[unit])
conf[unit][:page] = @params[:"#{unit}_#{@page_param}"] # requested page
if get_counts && (counts = get_counts.(unit, conf[unit][:period]))
conf[unit][:counts] = counts
if conf[unit][:leap]
requested_page = (conf[unit][:page] || 1).to_i
count_index = requested_page - 1
conf[unit][:page] = requested_page + counts[count_index..].index(&:positive?).to_i
end
end
calendar[unit] = object = Calendar.send(:create, unit, **conf[unit])
end
[replace(calendar), object.from, object.to]
end
Expand Down
9 changes: 3 additions & 6 deletions gem/lib/pagy/extras/calendar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@ def pagy_calendar(collection, conf)

conf[:pagy] ||= {}
unless conf.key?(:active) && !conf[:active]
calendar, from, to = Calendar.send(:init, conf, pagy_calendar_period(collection), params)
if respond_to?(:pagy_calendar_counts)
calendar.each_key do |unit|
calendar[unit].vars[:counts] = pagy_calendar_counts(collection, unit, *calendar[unit].vars[:period])
end
end
get_counts = ->(unit, period) { pagy_calendar_counts(collection, unit, *period) } \
if respond_to?(:pagy_calendar_counts)
calendar, from, to = Calendar.send(:init, conf, pagy_calendar_period(collection), params, get_counts)
collection = pagy_calendar_filter(collection, from, to)
end
pagy, results = send(conf[:pagy][:backend] || :pagy, collection, **conf[:pagy]) # use backend: :pagy when omitted
Expand Down
Binary file modified test/files/db/test.sqlite3
Binary file not shown.
18 changes: 0 additions & 18 deletions test/files/models.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,24 +95,6 @@ class Pet < ActiveRecord::Base
2021-12-27 12:18:57 +0000
2021-12-28 16:59:57 +0000
2021-12-31 15:10:23 +0000
2022-01-01 19:18:06 +0000
2022-01-03 08:36:27 +0000
2022-01-03 23:31:01 +0000
2022-01-05 02:14:57 +0000
2022-01-06 09:26:03 +0000
2022-01-07 20:22:22 +0000
2022-01-10 04:04:28 +0000
2022-01-11 17:17:55 +0000
2022-01-14 05:21:54 +0000
2022-01-16 01:18:58 +0000
2022-01-18 08:42:56 +0000
2022-01-19 00:45:04 +0000
2022-01-20 08:18:54 +0000
2022-01-22 05:26:38 +0000
2022-01-24 10:57:50 +0000
2022-01-26 09:47:02 +0000
2022-01-28 20:44:30 +0000
2022-01-31 16:19:50 +0000
2022-02-01 21:23:58 +0000
2022-02-04 14:41:57 +0000
2022-02-06 20:40:06 +0000
Expand Down
19 changes: 17 additions & 2 deletions test/pagy/extras/calendar_extra_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ def app(**opts)
_(calendar).must_be_nil
_(records.size).must_equal 20
_(pagy).must_be_instance_of Pagy
_(pagy.count).must_equal 505
_(pagy.pages).must_equal 26
_(pagy.count).must_equal 487
_(pagy.pages).must_equal 25
end
it 'raises NoMethodError for #pagy_calendar_period' do
error = assert_raises(NoMethodError) { MockApp.new.send(:pagy_calendar_period) }
Expand Down Expand Up @@ -306,4 +306,19 @@ def app(**opts)
_(app_counts.pagy_nav(calendar[:year], anchor_string: 'data-foo="bar"')).must_rematch :year
end
end
describe "Leap feature" do
c = MockApp::CalendarCounts
it "works with #{c} leap month" do
app_counts = c.new(params: { year_page: 2 })
calendar, _pagy, _entries = app_counts.send(:pagy_calendar,
Event.all,
year: {},
month: { leap: true },
day: { leap: true },
pagy: { limit: 10 })
_(app_counts.pagy_nav(calendar[:year])).must_rematch :year
_(app_counts.pagy_nav(calendar[:month])).must_rematch :month
_(app_counts.pagy_nav(calendar[:day])).must_rematch :day
end
end
end
Loading

0 comments on commit 7f8a832

Please sign in to comment.