pagy 5.1.1 → 5.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/lib/config/pagy.rb +17 -5
  3. data/lib/javascripts/pagy.js +1 -1
  4. data/lib/pagy/calendar.rb +148 -0
  5. data/lib/pagy/countless.rb +1 -1
  6. data/lib/pagy/exceptions.rb +2 -4
  7. data/lib/pagy/extras/arel.rb +2 -1
  8. data/lib/pagy/extras/array.rb +2 -2
  9. data/lib/pagy/extras/bootstrap.rb +1 -1
  10. data/lib/pagy/extras/bulma.rb +1 -1
  11. data/lib/pagy/extras/calendar.rb +46 -0
  12. data/lib/pagy/extras/countless.rb +3 -2
  13. data/lib/pagy/extras/elasticsearch_rails.rb +3 -2
  14. data/lib/pagy/extras/foundation.rb +2 -2
  15. data/lib/pagy/extras/gearbox.rb +3 -3
  16. data/lib/pagy/extras/headers.rb +6 -4
  17. data/lib/pagy/extras/i18n.rb +1 -1
  18. data/lib/pagy/extras/items.rb +4 -1
  19. data/lib/pagy/extras/materialize.rb +1 -1
  20. data/lib/pagy/extras/meilisearch.rb +3 -2
  21. data/lib/pagy/extras/metadata.rb +3 -2
  22. data/lib/pagy/extras/navs.rb +1 -1
  23. data/lib/pagy/extras/overflow.rb +24 -19
  24. data/lib/pagy/extras/searchkick.rb +3 -2
  25. data/lib/pagy/extras/semantic.rb +4 -4
  26. data/lib/pagy/extras/shared.rb +1 -1
  27. data/lib/pagy/extras/standalone.rb +10 -7
  28. data/lib/pagy/extras/support.rb +2 -1
  29. data/lib/pagy/extras/trim.rb +2 -1
  30. data/lib/pagy/extras/uikit.rb +2 -2
  31. data/lib/pagy/frontend.rb +9 -4
  32. data/lib/pagy/url_helpers.rb +5 -5
  33. data/lib/pagy.rb +2 -2
  34. data/lib/templates/foundation_nav.html.erb +1 -1
  35. data/lib/templates/foundation_nav.html.haml +1 -1
  36. data/lib/templates/foundation_nav.html.slim +1 -1
  37. data/lib/templates/uikit_nav.html.erb +1 -1
  38. data/lib/templates/uikit_nav.html.haml +1 -1
  39. data/lib/templates/uikit_nav.html.slim +1 -1
  40. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5300f9784ba9ab19522910b10e2f100a9823b5b52c91738966e946c91a08702a
4
- data.tar.gz: 2dc3599be82ee24dba9e8074c1b84e5443d69550ddec6fd32967f66a316ecedd
3
+ metadata.gz: 7e5a33b40f2a12b18d7a3a4d86d367836a2e5bce8e675fea912292558f41d7bf
4
+ data.tar.gz: d79570153a77422382c17eed7bf00c446c5cc13aadb237c7df3207fb57db3766
5
5
  SHA512:
6
- metadata.gz: 36b6893409fad1745593238f9a169623841dc4b55172fd2263f0bba09b3436e8c7f4e6f5ff6fc65bd56233b510daef44df60238189249547205f17087ddd69ab
7
- data.tar.gz: bddaf3afe21358ed1b9ed73de5585931f4dac9018cc37b30c268aae29cdd7f836ac4f77e4ea419f9268dc4f9f247907996ab2461cd6fc6a44d9e80467b513567
6
+ metadata.gz: 6e7881aac396c5049ecbdf6430d87a748e95f184bbe71b38d2c0b0cbc705cc0309c7148788534ea337a0236fae8591226d2158c78e34f06c4e557e29577f357c
7
+ data.tar.gz: 166af959cf2fb5b05746a5d0a1431f29775c13059f86402003a1f1a0fd8cbd0b13af58ab7a110fd5604266507a860c24df1b538378a5a28ff4932b68b482dc2d
data/lib/config/pagy.rb CHANGED
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Pagy initializer file (5.1.1)
3
+ # Pagy initializer file (5.2.1)
4
4
  # Customize only what you really need and notice that Pagy works also without any of the following lines.
5
5
  # Should you just cherry pick part of this file, please maintain the require-order of the extras
6
6
 
7
7
 
8
- # Pagy Variables
8
+ # Pagy DEFAULT Variables
9
9
  # See https://ddnexus.github.io/pagy/api/pagy#variables
10
- # All the Pagy::DEFAULT are set for all the Pagy instances but can be overridden
11
- # per instance by just passing them to Pagy.new or the #pagy controller method
10
+ # All the Pagy::DEFAULT are set for all the Pagy instances but can be overridden per instance
11
+ # by just passing them to Pagy.new|Pagy::Countless.new|Pagy::Calendar.new or the #pagy controller method
12
12
 
13
13
 
14
14
  # Instance variables
@@ -39,6 +39,18 @@
39
39
  # See https://ddnexus.github.io/pagy/extras/array
40
40
  # require 'pagy/extras/array'
41
41
 
42
+ # Calendar extra: Paginate a collection by calendar Time unit (year, month, week or day)
43
+ # See https://ddnexus.github.io/pagy/extras/calendar
44
+ # require 'pagy/extras/calendar'
45
+ # Pagy::DEFAULT[:local_minmax] = [] # Min and max local Time period must be set by the user (better not not as default)
46
+ # Pagy::DEFAULT[:unit] = :month # Time unit allowed %i[year month week day]
47
+ # Pagy::DEFAULT[:week_offset] = 0 # Day offset from Sunday (0: Sunday; 1: Monday;... 6: Saturday)
48
+ # Pagy::DEFAULT[:order] = :asc # Time direction of pagination
49
+ # Pagy::DEFAULT[:year_format] = '%Y' # strftime format for :year unit
50
+ # Pagy::DEFAULT[:month_format] = '%Y-%m' # strftime format for :month unit
51
+ # Pagy::DEFAULT[:week_format] = '%Y-%W' # strftime format for :week unit
52
+ # Pagy::DEFAULT[:day_format] = '%Y-%m-%d' # strftime format for :day unit
53
+
42
54
  # Countless extra: Paginate without any count, saving one query per rendering
43
55
  # See https://ddnexus.github.io/pagy/extras/countless
44
56
  # require 'pagy/extras/countless'
@@ -72,7 +84,7 @@
72
84
  # require 'pagy/extras/shared'
73
85
  # require 'pagy/extras/metadata'
74
86
  # For performance reason, you should explicitly set ONLY the metadata you use in the frontend
75
- # Pagy::DEFAULT[:metadata] = [:scaffold_url, :count, :page, :prev, :next, :last] # example
87
+ # Pagy::DEFAULT[:metadata] = %i[scaffold_url count page prev next last] # example
76
88
 
77
89
  # Searchkick extra: Paginate `Searchkick::Results` objects
78
90
  # See https://ddnexus.github.io/pagy/extras/searchkick
@@ -3,7 +3,7 @@
3
3
  // Container of the whole pagy stuff
4
4
  function Pagy(){}
5
5
 
6
- Pagy.version = '5.1.1'
6
+ Pagy.version = '5.2.1'
7
7
 
8
8
  // Used by the waitForMe function
9
9
  Pagy.delay = 100
@@ -0,0 +1,148 @@
1
+ # See Pagy::Countless API documentation: https://ddnexus.github.io/pagy/api/calendar
2
+ # frozen_string_literal: true
3
+
4
+ require 'pagy'
5
+ require 'date'
6
+
7
+ class Pagy # :nodoc:
8
+ DEFAULT[:local_minmax] = [] # Min and max Time period must be set by the user
9
+ DEFAULT[:unit] = :month # Time unit allowed %i[year month week day]
10
+ DEFAULT[:week_offset] = 0 # Day offset from Sunday (0: Sunday; 1: Monday;... 6: Saturday)
11
+ DEFAULT[:order] = :asc # Time direction of pagination
12
+ DEFAULT[:year_format] = '%Y' # strftime format for :year unit
13
+ DEFAULT[:month_format] = '%Y-%m' # strftime format for :month unit
14
+ DEFAULT[:week_format] = '%Y-%W' # strftime format for :week unit
15
+ DEFAULT[:day_format] = '%Y-%m-%d' # strftime format for :day unit
16
+
17
+ # Paginate a Time period by units (year, month, week or day)
18
+ class Calendar < Pagy
19
+ attr_reader :utc_from, :utc_to, :unit, :week_offset, :order
20
+ attr_writer :count, :in
21
+
22
+ # Merge and validate the options, do some simple arithmetic and set a few instance variables
23
+ def initialize(vars) # rubocop:disable Lint/MissingSuper
24
+ normalize_vars(vars)
25
+ setup_vars(page: 1, week_offset: 0)
26
+ setup_unit_vars
27
+ raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last
28
+
29
+ @prev = (@page - 1 unless @page == 1)
30
+ @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
31
+ end
32
+
33
+ # Generate a label for each page, with the specific `Time` period it refers to
34
+ def page_label(num = @page, format = nil)
35
+ snap = snap(num.to_i)
36
+ format ||= @vars[:"#{@unit}_format"]
37
+ case @unit
38
+ when :year then new_time(@initial.year + snap)
39
+ when :month then bump_month(@initial, snap)
40
+ when :week then @initial + (snap * WEEK)
41
+ when :day then @initial + (snap * DAY)
42
+ else raise InternalError, "expected @unit to be in [:year, :month, :week, :day]; got #{@unit.inspect}"
43
+ end.strftime(format)
44
+ end
45
+
46
+ def current_page_label(format = nil)
47
+ page_label(@page, format)
48
+ end
49
+
50
+ DAY = 60 * 60 * 24
51
+ WEEK = DAY * 7
52
+
53
+ protected
54
+
55
+ def setup_unit_vars
56
+ (units = %i[year month week day]).each do |unit|
57
+ raise VariableError.new(self, :format, 'to be a strftime format', @vars[:"#{unit}_format"]) \
58
+ unless @vars[:"#{unit}_format"].is_a?(String)
59
+ end
60
+ raise VariableError.new(self, :unit, "to be in #{units.inspect}", @unit) \
61
+ unless units.include?(@unit = @vars[:unit])
62
+ raise VariableError.new(self, :order, 'to be in [:asc, :desc]', @order) \
63
+ unless %i[asc desc].include?(@order = @vars[:order])
64
+
65
+ min, max = @vars[:local_minmax]
66
+ raise VariableError.new(self, :local_minmax, 'to be a an Array of min and max local Time instances', @vars[:local_minmax]) \
67
+ unless min.is_a?(Time) && max.is_a?(Time) && !min.utc? && !min.utc? && min <= max \
68
+ && (@utc_offset = min.utc_offset) == max.utc_offset
69
+
70
+ send :"setup_#{@unit}_vars", min, max
71
+ end
72
+
73
+ # IMPORTANT: all the Time objects created and passed as arguments MUST be local!
74
+
75
+ # @initial: beginning of the first day of the period that encloses the min local time
76
+ # @final: beginning of the first day of the NEXT period AFTER the period that encloses the max local time
77
+ # @utc_from: beginning of the first day of the period of the current page as UTC time
78
+ # @utc_to: beginning of the first day of the NEXT period AFTER the current page as UTC time
79
+
80
+ # Setup the calendar vars when the unit is :year
81
+ def setup_year_vars(min, max)
82
+ @initial = new_time(min.year)
83
+ @final = new_time(max.year + 1)
84
+ @pages = @last = @final.year - @initial.year
85
+ @utc_from = new_time(@initial.year + snap).utc
86
+ @utc_to = new_time(@initial.year + snap + 1).utc
87
+ end
88
+
89
+ # Setup the calendar vars when the unit is :month
90
+ def setup_month_vars(min, max)
91
+ @initial = new_time(min.year, min.month)
92
+ @final = bump_month(max)
93
+ @pages = @last = months(@final) - months(@initial)
94
+ @utc_from = bump_month(@initial, snap).utc
95
+ @utc_to = bump_month(@initial, snap + 1).utc
96
+ end
97
+
98
+ # Setup the calendar vars when the unit is :week
99
+ def setup_week_vars(min, max)
100
+ @initial = week_start(min)
101
+ @final = week_start(max) + WEEK
102
+ @pages = @last = (@final - @initial).to_i / WEEK
103
+ @utc_from = (@initial + (snap * WEEK)).utc
104
+ @utc_to = @utc_from + WEEK
105
+ end
106
+
107
+ # Setup the calendar vars when the unit is :day
108
+ def setup_day_vars(min, max)
109
+ @initial = new_time(min.year, min.month, min.day)
110
+ @final = new_time(max.year, max.month, max.day) + DAY
111
+ @pages = @last = (@final - @initial).to_i / DAY
112
+ @utc_from = (@initial + (snap * DAY)).utc
113
+ @utc_to = @utc_from + DAY
114
+ end
115
+
116
+ private
117
+
118
+ # Simple trick to snap the page into its ordered position,
119
+ # without actually reordering anything in the internal structure
120
+ def snap(page = @page)
121
+ @order == :asc ? page - 1 : @pages - page
122
+ end
123
+
124
+ # Create a new local time at the beginning of the day
125
+ def new_time(year, month = 1, day = 1)
126
+ Time.new(year, month, day, 0, 0, 0, @utc_offset)
127
+ end
128
+
129
+ # Months in local time
130
+ def months(time)
131
+ (time.year * 12) + time.month
132
+ end
133
+
134
+ # Add 1 or more months to local time
135
+ def bump_month(time, months = 1)
136
+ months += months(time)
137
+ year = months / 12
138
+ month = months % 12
139
+ month.zero? ? new_time(year - 1, 12) : new_time(year, month)
140
+ end
141
+
142
+ # Return the start of the week for local time
143
+ def week_start(time)
144
+ start = time - (((time.wday - @week_offset) * DAY) % WEEK)
145
+ new_time(start.year, start.month, start.day)
146
+ end
147
+ end
148
+ end
@@ -16,7 +16,7 @@ class Pagy
16
16
 
17
17
  # Finalize the instance variables based on the fetched size
18
18
  def finalize(fetched_size)
19
- raise OverflowError.new(self, :page, "to be < #{@page}") if fetched_size.zero? && @page > 1
19
+ raise OverflowError.new(self, :page, "to be < #{@page}", @page) if fetched_size.zero? && @page > 1
20
20
 
21
21
  @pages = @last = (fetched_size > @items ? @page + 1 : @page)
22
22
  @in = [fetched_size, @items].min
@@ -6,13 +6,11 @@ class Pagy
6
6
  attr_reader :pagy, :variable, :value
7
7
 
8
8
  # Set the variables and prepare the message
9
- def initialize(pagy, variable, description, value = nil)
9
+ def initialize(pagy, variable, description, value)
10
10
  @pagy = pagy
11
11
  @variable = variable
12
12
  @value = value
13
- message = +"expected :#{@variable} #{description}"
14
- message << "; got #{@value.inspect}" if value
15
- super message
13
+ super "expected :#{@variable} #{description}; got #{@value.inspect}"
16
14
  end
17
15
  end
18
16
 
@@ -1,7 +1,8 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/arel
2
2
  # frozen_string_literal: true
3
3
 
4
- class Pagy
4
+ class Pagy # :nodoc:
5
+ # Better performance of grouped ActiveRecord collections
5
6
  module ArelExtra
6
7
  private
7
8
 
@@ -1,8 +1,8 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/array
2
2
  # frozen_string_literal: true
3
3
 
4
- class Pagy
5
- # Add specialized backend methods to paginate array collections
4
+ class Pagy # :nodoc:
5
+ # Paginate arrays efficiently, avoiding expensive array-wrapping and without overriding
6
6
  module ArrayExtra
7
7
  private
8
8
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  require 'pagy/extras/shared'
5
5
 
6
- class Pagy
6
+ class Pagy # :nodoc:
7
7
  # Frontend modules are specially optimized for performance.
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module BootstrapExtra
@@ -3,7 +3,7 @@
3
3
 
4
4
  require 'pagy/extras/shared'
5
5
 
6
- class Pagy
6
+ class Pagy # :nodoc:
7
7
  # Frontend modules are specially optimized for performance.
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module BulmaExtra
@@ -0,0 +1,46 @@
1
+ # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/calendar
2
+ # frozen_string_literal: true
3
+
4
+ require 'pagy/calendar'
5
+
6
+ class Pagy # :nodoc:
7
+ # Paginate based on calendar periods (year month week day)
8
+ module CalendarExtra
9
+ # Additions for the Backend module
10
+ module Backend
11
+ private
12
+
13
+ # Return Pagy object and items
14
+ def pagy_calendar(collection, vars = {})
15
+ pagy = Calendar.new(pagy_calendar_get_vars(collection, vars))
16
+ [pagy, pagy_calendar_get_items(collection, pagy)]
17
+ end
18
+
19
+ # Sub-method called only by #pagy_calendar: here for easy customization of variables by overriding.
20
+ # You may want to override it in order to implement the dynamic set of the :minmax variable.
21
+ def pagy_calendar_get_vars(_collection, vars)
22
+ # vars[:minmax] ||= your_own_method_to_get_the_period_from(collection)
23
+ vars[:page] ||= params[vars[:page_param] || DEFAULT[:page_param]]
24
+ vars
25
+ end
26
+
27
+ # This method should be implemented in the application and should return the records
28
+ # for the unit by selecting the records with DateTime from pagy.from to pagy.to
29
+ def pagy_calendar_get_items(_collection, _pagy)
30
+ # collection.your_own_method_to_get_the_items_with(pagy.from, pagy.to)
31
+ raise NoMethodError, 'The pagy_calendar_get_items method must be implemented in the application and must return ' \
32
+ 'the items for the unit by selecting the records with Time from pagy.from to pagy.to'
33
+ end
34
+ end
35
+
36
+ # Additions for the Frontend module
37
+ module Frontend
38
+ # Change the text shown in the nav bar links to the actual unit of each page.
39
+ def pagy_labeler(pagy, num)
40
+ pagy.is_a?(Calendar) ? pagy.page_label(num) : num
41
+ end
42
+ end
43
+ end
44
+ Backend.prepend CalendarExtra::Backend
45
+ Frontend.prepend CalendarExtra::Frontend
46
+ end
@@ -3,15 +3,16 @@
3
3
 
4
4
  require 'pagy/countless'
5
5
 
6
- class Pagy
6
+ class Pagy # :nodoc:
7
7
  DEFAULT[:countless_minimal] = false
8
8
 
9
+ # Paginate without the need of any count, saving one query per rendering
9
10
  module CountlessExtra
10
11
  private
11
12
 
12
13
  # Return Pagy object and items
13
14
  def pagy_countless(collection, vars = {})
14
- pagy = Pagy::Countless.new(pagy_countless_get_vars(collection, vars))
15
+ pagy = Countless.new(pagy_countless_get_vars(collection, vars))
15
16
  [pagy, pagy_countless_get_items(collection, pagy)]
16
17
  end
17
18
 
@@ -1,9 +1,10 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/elasticsearch_rails
2
2
  # frozen_string_literal: true
3
3
 
4
- class Pagy
4
+ class Pagy # :nodoc:
5
5
  DEFAULT[:elasticsearch_rails_search_method] ||= :pagy_search
6
6
 
7
+ # Paginate ElasticsearchRails response objects
7
8
  module ElasticsearchRailsExtra
8
9
  module_function
9
10
 
@@ -17,7 +18,7 @@ class Pagy
17
18
  total.is_a?(Hash) ? total['value'] : total
18
19
  end
19
20
 
20
- module ElasticsearchRails
21
+ module ElasticsearchRails # :nodoc:
21
22
  # Return an array used to delay the call of #search
22
23
  # after the pagination variables are merged to the options.
23
24
  # It also pushes to the same array an optional method call.
@@ -3,7 +3,7 @@
3
3
 
4
4
  require 'pagy/extras/shared'
5
5
 
6
- class Pagy
6
+ class Pagy # :nodoc:
7
7
  # Frontend modules are specially optimized for performance.
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module FoundationExtra
@@ -17,7 +17,7 @@ class Pagy
17
17
  pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
18
18
  html << case item
19
19
  when Integer then %(<li>#{link.call item}</li>) # page link
20
- when String then %(<li class="current">#{item}</li>) # active page
20
+ when String then %(<li class="current">#{pagy_labeler(pagy, item)}</li>) # active page
21
21
  when :gap then %(<li class="ellipsis gap" aria-hidden="true"></li>) # page gap
22
22
  else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
23
23
  end
@@ -1,14 +1,14 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/gearbox
2
2
  # frozen_string_literal: true
3
3
 
4
- class Pagy
4
+ class Pagy # :nodoc:
5
5
  DEFAULT[:gearbox_extra] = true # extra enabled by default
6
6
  DEFAULT[:gearbox_items] = [15, 30, 60, 100]
7
7
 
8
8
  # Automatically change the number of items per page depending on the page number
9
9
  # accepts an array as the :gearbox_items variable, that will determine the items for the first pages
10
10
  module GearboxExtra
11
- # Setup @items based on the :items variable
11
+ # Setup @items based on the :gearbox_items variable
12
12
  def setup_items_var
13
13
  return super if !@vars[:gearbox_extra] || @vars[:items_extra]
14
14
 
@@ -19,7 +19,7 @@ class Pagy
19
19
  @items = gearbox_items[@page - 1] || gearbox_items.last
20
20
  end
21
21
 
22
- # Setup @pages and @last based on the :items variable
22
+ # Setup @pages and @last based on the :gearbox_items variable
23
23
  def setup_pages_var
24
24
  return super if !@vars[:gearbox_extra] || @vars[:items_extra]
25
25
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  require 'pagy/url_helpers'
5
5
 
6
- class Pagy
6
+ class Pagy # :nodoc:
7
7
  DEFAULT[:headers] = { page: 'Current-Page',
8
8
  items: 'Page-Items',
9
9
  count: 'Total-Count',
@@ -38,11 +38,13 @@ class Pagy
38
38
  end.compact.to_h
39
39
  hash = { 'Link' => link }
40
40
  headers = pagy.vars[:headers]
41
- hash[headers[:page]] = pagy.page.to_s if headers[:page]
42
- hash[headers[:items]] = pagy.vars[:items].to_s if headers[:items]
41
+ hash[headers[:page]] = pagy.page.to_s if headers[:page]
42
+ if headers[:items] && !(defined?(Pagy::Calendar) && pagy.is_a?(Pagy::Calendar)) # not for Calendar
43
+ hash[headers[:items]] = pagy.vars[:items].to_s
44
+ end
43
45
  unless countless
44
46
  hash[headers[:pages]] = pagy.pages.to_s if headers[:pages]
45
- hash[headers[:count]] = pagy.count.to_s if headers[:count]
47
+ hash[headers[:count]] = pagy.count.to_s if pagy.count && headers[:count] # count may be nil with Calendar
46
48
  end
47
49
  hash
48
50
  end
@@ -1,7 +1,7 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/i18n
2
2
  # frozen_string_literal: true
3
3
 
4
- class Pagy
4
+ class Pagy # :nodoc:
5
5
  # Use ::I18n gem
6
6
  module I18nExtra
7
7
  def pagy_t(key, **opts)
@@ -3,12 +3,14 @@
3
3
 
4
4
  require 'pagy/extras/shared'
5
5
 
6
- class Pagy # Default variables for this extra
6
+ class Pagy # :nodoc:
7
7
  DEFAULT[:items_param] = :items
8
8
  DEFAULT[:max_items] = 100
9
9
  DEFAULT[:items_extra] = true # extra enabled by default
10
10
 
11
+ # Allow the client to request a custom number of items per page with an optional selector UI
11
12
  module ItemsExtra
13
+ # Additions for the Backend module
12
14
  module Backend
13
15
  private
14
16
 
@@ -22,6 +24,7 @@ class Pagy # Default variables for this extra
22
24
  end
23
25
  end
24
26
 
27
+ # Additions for the Frontend module
25
28
  module Frontend
26
29
  ITEMS_PLACEHOLDER = '__pagy_items__'
27
30
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  require 'pagy/extras/shared'
5
5
 
6
- class Pagy
6
+ class Pagy # :nodoc:
7
7
  # Frontend modules are specially optimized for performance.
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module MaterializeExtra
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Pagy
3
+ class Pagy # :nodoc:
4
4
  DEFAULT[:meilisearch_search_method] ||= :pagy_search
5
5
 
6
+ # Paginate Meilisearch results
6
7
  module MeilisearchExtra
7
- module Meilisearch
8
+ module Meilisearch # :nodoc:
8
9
  # Return an array used to delay the call of #search
9
10
  # after the pagination variables are merged to the options
10
11
  def pagy_meilisearch(term = nil, **vars)
@@ -3,7 +3,7 @@
3
3
 
4
4
  require 'pagy/url_helpers'
5
5
 
6
- class Pagy
6
+ class Pagy # :nodoc:
7
7
  DEFAULT[:metadata] = %i[ scaffold_url first_url prev_url page_url next_url last_url
8
8
  count page items vars pages last in from to prev next series ]
9
9
 
@@ -17,7 +17,8 @@ class Pagy
17
17
  def pagy_metadata(pagy, absolute: nil)
18
18
  scaffold_url = pagy_url_for(pagy, PAGE_PLACEHOLDER, absolute: absolute)
19
19
  {}.tap do |metadata|
20
- pagy.vars[:metadata].each do |key|
20
+ keys = pagy.is_a?(Calendar) ? pagy.vars[:metadata] - %i[count items] : pagy.vars[:metadata]
21
+ keys.each do |key|
21
22
  metadata[key] = case key
22
23
  when :scaffold_url then scaffold_url
23
24
  when :first_url then scaffold_url.sub(PAGE_PLACEHOLDER, 1.to_s)
@@ -3,7 +3,7 @@
3
3
 
4
4
  require 'pagy/extras/shared'
5
5
 
6
- class Pagy
6
+ class Pagy # :nodoc:
7
7
  # Frontend modules are specially optimized for performance.
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module NavsExtra
@@ -1,10 +1,10 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/overflow
2
2
  # frozen_string_literal: true
3
3
 
4
- class Pagy
4
+ class Pagy # :nodoc:
5
5
  DEFAULT[:overflow] = :empty_page
6
6
 
7
- # Handles OverflowError exceptions with different options
7
+ # Handles OverflowError exceptions for different classes with different options
8
8
  module OverflowExtra
9
9
  # Support for Pagy class
10
10
  module Pagy
@@ -15,21 +15,25 @@ class Pagy
15
15
 
16
16
  # Add rescue clause for different behaviors
17
17
  def initialize(vars)
18
- @overflow ||= false # don't override if :last_page re-run the method after an overflow
18
+ @overflow ||= false # still true if :last_page re-run the method after an overflow
19
19
  super
20
20
  rescue OverflowError
21
- @overflow = true # add the overflow flag
21
+ @overflow = true # add the overflow flag
22
22
  case @vars[:overflow]
23
23
  when :exception
24
- raise # same as without the extra
24
+ raise # same as without the extra
25
25
  when :last_page
26
- initial_page = @vars[:page] # save the very initial page (even after re-run)
27
- initialize vars.merge!(page: @last) # re-run with the last page
28
- @vars[:page] = initial_page # restore the initial page
26
+ requested_page = @vars[:page] # save the requested page (even after re-run)
27
+ initialize vars.merge!(page: @last) # re-run with the last page
28
+ @vars[:page] = requested_page # restore the requested page
29
29
  when :empty_page
30
- @offset = @items = @from = @to = 0 # vars relative to the actual page
31
- @prev = @last # prev relative to the actual page
32
- extend Series # special series for :empty_page
30
+ @offset = @in = @from = @to = 0 # vars relative to the actual page
31
+ if is_a?(Calendar) # only for Calendar instances
32
+ edge = @order == :asc ? @final : @initial # get the edge of the overflow side (neat, but it would work with any time)
33
+ @utc_from = @utc_to = edge.getutc # set both to the edge utc time (a query with >= && < will get no record)
34
+ end
35
+ @prev = @last # prev relative to the actual page
36
+ extend Series # special series for :empty_page
33
37
  else
34
38
  raise VariableError.new(self, :overflow, 'to be in [:last_page, :empty_page, :exception]', @vars[:overflow])
35
39
  end
@@ -38,10 +42,10 @@ class Pagy
38
42
  # Special series for empty page
39
43
  module Series
40
44
  def series(size = @vars[:size])
41
- @page = @last # series for last page
42
- super(size).tap do |s| # call original series
43
- s[s.index(@page.to_s)] = @page # string to integer (i.e. no current page)
44
- @page = @vars[:page] # restore the actual page
45
+ @page = @last # series for last page
46
+ super(size).tap do |s| # call original series
47
+ s[s.index(@page.to_s)] = @page # string to integer (i.e. no current page)
48
+ @page = @vars[:page] # restore the actual page
45
49
  end
46
50
  end
47
51
  end
@@ -54,13 +58,13 @@ class Pagy
54
58
  @overflow = false
55
59
  super
56
60
  rescue OverflowError
57
- @overflow = true # add the overflow flag
61
+ @overflow = true # add the overflow flag
58
62
  case @vars[:overflow]
59
63
  when :exception
60
- raise # same as without the extra
64
+ raise # same as without the extra
61
65
  when :empty_page
62
- @offset = @items = @from = @to = 0 # vars relative to the actual page
63
- @vars[:size] = [] # no page in the series
66
+ @offset = @in = @from = @to = 0 # vars relative to the actual page
67
+ @vars[:size] = [] # no page in the series
64
68
  self
65
69
  else
66
70
  raise VariableError.new(self, :overflow, 'to be in [:empty_page, :exception]', @vars[:overflow])
@@ -69,5 +73,6 @@ class Pagy
69
73
  end
70
74
  end
71
75
  prepend OverflowExtra::Pagy
76
+ Calendar.prepend OverflowExtra::Pagy if defined?(Calendar)
72
77
  Countless.prepend OverflowExtra::Countless if defined?(Countless)
73
78
  end
@@ -1,11 +1,12 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/searchkick
2
2
  # frozen_string_literal: true
3
3
 
4
- class Pagy
4
+ class Pagy # :nodoc:
5
5
  DEFAULT[:searchkick_search_method] ||= :pagy_search
6
6
 
7
+ # Paginate Searchkick::Results objects
7
8
  module SearchkickExtra
8
- module Searchkick
9
+ module Searchkick # :nodoc:
9
10
  # Return an array used to delay the call of #search
10
11
  # after the pagination variables are merged to the options.
11
12
  # It also pushes to the same array an optional method call.
@@ -3,7 +3,7 @@
3
3
 
4
4
  require 'pagy/extras/shared'
5
5
 
6
- class Pagy
6
+ class Pagy # :nodoc:
7
7
  # Frontend modules are specially optimized for performance.
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module SemanticExtra
@@ -16,9 +16,9 @@ class Pagy
16
16
  html << pagy_semantic_prev_html(pagy, link)
17
17
  pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
18
18
  html << case item
19
- when Integer then link.call item # page link
20
- when String then %(<a class="item active">#{item}</a>) # current page
21
- when :gap then %(<div class="disabled item">#{pagy_t 'pagy.nav.gap'}</div>) # page gap
19
+ when Integer then link.call item
20
+ when String then %(<a class="item active">#{pagy_labeler(pagy, item)}</a>)
21
+ when :gap then %(<div class="disabled item">#{pagy_t 'pagy.nav.gap'}</div>)
22
22
  else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
23
23
  end
24
24
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'digest'
4
4
 
5
- class Pagy
5
+ class Pagy # :nodoc:
6
6
  DEFAULT[:steps] = false # default false will use {0 => @vars[:size]}
7
7
 
8
8
  module SharedExtra
@@ -2,7 +2,10 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'uri'
5
- class Pagy
5
+
6
+ class Pagy # :nodoc:
7
+ # Use pagy without any request object, nor Rack environment/gem, nor any defined params method,
8
+ # even in the irb/rails console without any app or config.
6
9
  module StandaloneExtra
7
10
  # Extracted from Rack::Utils and reformatted for rubocop
8
11
  module QueryUtils
@@ -34,15 +37,15 @@ class Pagy
34
37
  # it works exactly as the regular #pagy_url_for, relying on the params method and Rack.
35
38
  # If there is a defined pagy.vars[:url] variable it does not need the params method nor Rack.
36
39
  def pagy_url_for(pagy, page, absolute: nil)
37
- p_vars = pagy.vars
38
- return super unless (url = p_vars[:url])
40
+ vars = pagy.vars
41
+ return super unless (url = vars[:url])
39
42
 
40
- params = p_vars[:params]
41
- params[p_vars[:page_param].to_s] = page
42
- params[p_vars[:items_param].to_s] = p_vars[:items] if defined?(ItemsExtra)
43
+ params = vars[:params].clone # safe when it gets reused
44
+ params[vars[:page_param]] = page
45
+ params[vars[:items_param]] = vars[:items] if vars[:items_extra]
43
46
 
44
47
  query_string = "?#{QueryUtils.build_nested_query(pagy_massage_params(params))}"
45
- "#{url}#{query_string}#{p_vars[:fragment]}"
48
+ "#{url}#{query_string}#{vars[:fragment]}"
46
49
  end
47
50
  end
48
51
  # In ruby 3+ `UrlHelpers.prepend StandaloneExtra` would be enough instead of using the next 2 lines
@@ -1,7 +1,8 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/support
2
2
  # frozen_string_literal: true
3
3
 
4
- class Pagy
4
+ class Pagy # :nodoc:
5
+ # Extra support for features like: incremental, auto-incremental and infinite pagination
5
6
  module SupportExtra
6
7
  # Return the previous page URL string or nil
7
8
  def pagy_prev_url(pagy)
@@ -1,9 +1,10 @@
1
1
  # See the Pagy documentation: https://ddnexus.github.io/pagy/extras/trim
2
2
  # frozen_string_literal: true
3
3
 
4
- class Pagy
4
+ class Pagy # :nodoc:
5
5
  DEFAULT[:trim_extra] = true # extra enabled by default
6
6
 
7
+ # Remove the page=1 param from the first page link
7
8
  module TrimExtra
8
9
  # Override the original pagy_link_proc.
9
10
  # Call the pagy_trim method if the trim_extra is enabled.
@@ -3,7 +3,7 @@
3
3
 
4
4
  require 'pagy/extras/shared'
5
5
 
6
- class Pagy
6
+ class Pagy # :nodoc:
7
7
  # Frontend modules are specially optimized for performance.
8
8
  # The resulting code may not look very elegant, but produces the best benchmarks
9
9
  module UikitExtra
@@ -16,7 +16,7 @@ class Pagy
16
16
  pagy.series.each do |item|
17
17
  html << case item
18
18
  when Integer then %(<li>#{link.call item}</li>)
19
- when String then %(<li class="uk-active"><span>#{item}</span></li>)
19
+ when String then %(<li class="uk-active"><span>#{pagy_labeler(pagy, item)}</span></li>)
20
20
  when :gap then %(<li class="uk-disabled"><span>#{pagy_t 'pagy.nav.gap'}</span></li>)
21
21
  else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
22
22
  end
data/lib/pagy/frontend.rb CHANGED
@@ -28,9 +28,9 @@ class Pagy
28
28
  end
29
29
  pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
30
30
  html << case item
31
- when Integer then %(<span class="page">#{link.call item}</span> ) # page link
32
- when String then %(<span class="page active">#{item}</span> ) # current page
33
- when :gap then %(<span class="page gap">#{pagy_t('pagy.nav.gap')}</span> ) # page gap
31
+ when Integer then %(<span class="page">#{link.call item}</span> )
32
+ when String then %(<span class="page active">#{pagy_labeler(pagy, item)}</span> )
33
+ when :gap then %(<span class="page gap">#{pagy_t('pagy.nav.gap')}</span> )
34
34
  else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
35
35
  end
36
36
  end
@@ -64,7 +64,7 @@ class Pagy
64
64
  p_next = pagy.next
65
65
  left, right = %(<a href="#{pagy_url_for pagy, PAGE_PLACEHOLDER}" #{
66
66
  pagy.vars[:link_extra]} #{link_extra}).split(PAGE_PLACEHOLDER, 2)
67
- lambda do |num, text = num, extra_attrs = ''|
67
+ lambda do |num, text = pagy_labeler(pagy, num), extra_attrs = ''|
68
68
  %(#{left}#{num}#{right}#{ case num
69
69
  when p_prev then ' rel="prev"'
70
70
  when p_next then ' rel="next"'
@@ -73,6 +73,11 @@ class Pagy
73
73
  end
74
74
  end
75
75
 
76
+ # Allow customization of the output by overriding (used by the calendar extra)
77
+ def pagy_labeler(_pagy, num)
78
+ num
79
+ end
80
+
76
81
  # Similar to I18n.t: just ~18x faster using ~10x less memory
77
82
  # (@pagy_locale explicitly initialized in order to avoid warning)
78
83
  def pagy_t(key, **opts)
@@ -7,13 +7,13 @@ class Pagy
7
7
  # It supports all Rack-based frameworks (Sinatra, Padrino, Rails, ...).
8
8
  # For non-rack environments you can use the standalone extra
9
9
  def pagy_url_for(pagy, page, absolute: nil)
10
- p_vars = pagy.vars
11
- params = request.GET.merge(p_vars[:params])
12
- params[p_vars[:page_param].to_s] = page
13
- params[p_vars[:items_param].to_s] = p_vars[:items] if defined?(ItemsExtra)
10
+ vars = pagy.vars
11
+ params = request.GET.merge(vars[:params].transform_keys(&:to_s))
12
+ params[vars[:page_param].to_s] = page
13
+ params[vars[:items_param].to_s] = vars[:items] if vars[:items_extra]
14
14
 
15
15
  query_string = "?#{Rack::Utils.build_nested_query(pagy_massage_params(params))}"
16
- "#{request.base_url if absolute}#{request.path}#{query_string}#{p_vars[:fragment]}"
16
+ "#{request.base_url if absolute}#{request.path}#{query_string}#{vars[:fragment]}"
17
17
  end
18
18
 
19
19
  # Sub-method called only by #pagy_url_for: here for easy customization of params by overriding
data/lib/pagy.rb CHANGED
@@ -5,7 +5,7 @@ require 'pathname'
5
5
 
6
6
  # Core class
7
7
  class Pagy
8
- VERSION = '5.1.1'
8
+ VERSION = '5.2.1'
9
9
 
10
10
  # Root pathname to get the path of Pagy files like templates or dictionaries
11
11
  def self.root
@@ -46,7 +46,7 @@ class Pagy
46
46
  def series(size = @vars[:size])
47
47
  return [] if size.empty?
48
48
  raise VariableError.new(self, :size, 'to contain 4 items >= 0', size) \
49
- unless size.size == 4 && size.all? { |num| !num.negative? rescue false } # rubocop:disable Style/RescueModifier
49
+ unless size.is_a?(Array) && size.size == 4 && size.all? { |num| !num.negative? rescue false } # rubocop:disable Style/RescueModifier
50
50
 
51
51
  # This algorithm is up to ~5x faster and ~2.3x lighter than the previous one (pagy < 4.3)
52
52
  left_gap_start = 1 + size[0] # rubocop:disable Layout/ExtraSpacing, Layout/SpaceAroundOperators
@@ -13,7 +13,7 @@
13
13
  <% end -%>
14
14
  <% pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36] -%>
15
15
  <% if item.is_a?(Integer) -%> <li><%== link.call(item) %></li>
16
- <% elsif item.is_a?(String) -%> <li class="current"><%= item %></li>
16
+ <% elsif item.is_a?(String) -%> <li class="current"><%= pagy_labeler(pagy, item) %></li>
17
17
  <% elsif item == :gap -%> <li class="ellipsis gap" aria-hidden="true"></li>
18
18
  <% end -%>
19
19
  <% end -%>
@@ -22,7 +22,7 @@
22
22
 
23
23
  - elsif item.is_a?(String) # current page
24
24
  %li.current
25
- = item
25
+ = pagy_labeler(pagy, item)
26
26
 
27
27
  - elsif item == :gap # page gap
28
28
  %li.ellipsis.gap{"aria-hidden" => true}
@@ -22,7 +22,7 @@ nav.pagy-foundation-nav role="navigation" aria-label="Pagination"
22
22
 
23
23
  - elsif item.is_a?(String) # current page
24
24
  li.current
25
- = item
25
+ = pagy_labeler(pagy, item)
26
26
 
27
27
  - elsif item == :gap # page gap
28
28
  li.ellipsis.gap aria-hidden="true"
@@ -5,7 +5,7 @@
5
5
  <% end -%>
6
6
  <% pagy.series.each do |item| -%>
7
7
  <% if item.is_a?(Integer) -%> <li><%== link.call(item) %></li>
8
- <% elsif item.is_a?(String) -%> <li class="uk-active"><span><%== item %></span></li>
8
+ <% elsif item.is_a?(String) -%> <li class="uk-active"><span><%== pagy_labeler(pagy, item) %></span></li>
9
9
  <% elsif item == :gap -%> <li class="uk-disabled"><span><%== pagy_t('pagy.nav.gap') %></span></li>
10
10
  <% end -%>
11
11
  <% end -%>
@@ -14,7 +14,7 @@
14
14
 
15
15
  - elsif item.is_a?(String)
16
16
  %li.uk-active
17
- %span!= item
17
+ %span!= pagy_labeler(pagy, item)
18
18
 
19
19
  - elsif item == :gap
20
20
  %li.uk-disabled
@@ -14,7 +14,7 @@ ul.uk-pagination.uk-flex-center
14
14
 
15
15
  - elsif item.is_a?(String)
16
16
  li.uk-active
17
- span== item
17
+ span== pagy_labeler(pagy, item)
18
18
 
19
19
  - elsif item == :gap
20
20
  li.uk-disabled
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pagy
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.1
4
+ version: 5.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Domizio Demichelis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-25 00:00:00.000000000 Z
11
+ date: 2021-11-07 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Agnostic pagination in plain ruby. It does it all. Better.
14
14
  email:
@@ -53,6 +53,7 @@ files:
53
53
  - lib/locales/zh-TW.yml
54
54
  - lib/pagy.rb
55
55
  - lib/pagy/backend.rb
56
+ - lib/pagy/calendar.rb
56
57
  - lib/pagy/console.rb
57
58
  - lib/pagy/countless.rb
58
59
  - lib/pagy/exceptions.rb
@@ -60,6 +61,7 @@ files:
60
61
  - lib/pagy/extras/array.rb
61
62
  - lib/pagy/extras/bootstrap.rb
62
63
  - lib/pagy/extras/bulma.rb
64
+ - lib/pagy/extras/calendar.rb
63
65
  - lib/pagy/extras/countless.rb
64
66
  - lib/pagy/extras/elasticsearch_rails.rb
65
67
  - lib/pagy/extras/foundation.rb