pagy 4.11.0 → 5.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/config/pagy.rb +71 -45
  3. data/lib/javascripts/pagy.js +15 -6
  4. data/lib/pagy/backend.rb +9 -12
  5. data/lib/pagy/console.rb +6 -4
  6. data/lib/pagy/countless.rb +21 -23
  7. data/lib/pagy/exceptions.rb +16 -16
  8. data/lib/pagy/extras/arel.rb +6 -6
  9. data/lib/pagy/extras/array.rb +6 -6
  10. data/lib/pagy/extras/bootstrap.rb +35 -29
  11. data/lib/pagy/extras/bulma.rb +43 -32
  12. data/lib/pagy/extras/countless.rb +12 -16
  13. data/lib/pagy/extras/elasticsearch_rails.rb +64 -47
  14. data/lib/pagy/extras/foundation.rb +29 -26
  15. data/lib/pagy/extras/gearbox.rb +42 -0
  16. data/lib/pagy/extras/headers.rb +24 -16
  17. data/lib/pagy/extras/i18n.rb +7 -16
  18. data/lib/pagy/extras/items.rb +38 -39
  19. data/lib/pagy/extras/materialize.rb +31 -30
  20. data/lib/pagy/extras/meilisearch.rb +50 -45
  21. data/lib/pagy/extras/metadata.rb +14 -20
  22. data/lib/pagy/extras/navs.rb +26 -26
  23. data/lib/pagy/extras/overflow.rb +56 -60
  24. data/lib/pagy/extras/searchkick.rb +51 -45
  25. data/lib/pagy/extras/semantic.rb +31 -30
  26. data/lib/pagy/extras/shared.rb +43 -40
  27. data/lib/pagy/extras/standalone.rb +39 -43
  28. data/lib/pagy/extras/support.rb +20 -13
  29. data/lib/pagy/extras/trim.rb +11 -11
  30. data/lib/pagy/extras/uikit.rb +30 -28
  31. data/lib/pagy/frontend.rb +25 -49
  32. data/lib/pagy/i18n.rb +159 -0
  33. data/lib/pagy/url_helpers.rb +24 -0
  34. data/lib/pagy.rb +54 -29
  35. data/lib/templates/uikit_nav.html.erb +1 -1
  36. data/lib/templates/uikit_nav.html.slim +1 -1
  37. metadata +7 -10
  38. data/lib/locales/utils/i18n.rb +0 -17
  39. data/lib/locales/utils/loader.rb +0 -31
  40. data/lib/locales/utils/p11n.rb +0 -112
  41. data/lib/pagy/deprecation.rb +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed7987ef93f9d2d45f8b37c7d8c62546bb08b658699d4fdacf7e06b2e5abdefe
4
- data.tar.gz: d2330d05cbf068d938425ed64ec3a0b0a16cf86d36cd2a2b2d8fc2568942a2d3
3
+ metadata.gz: 5300f9784ba9ab19522910b10e2f100a9823b5b52c91738966e946c91a08702a
4
+ data.tar.gz: 2dc3599be82ee24dba9e8074c1b84e5443d69550ddec6fd32967f66a316ecedd
5
5
  SHA512:
6
- metadata.gz: c938d41fae6e33cfd0d569655b134f2d239fe44f6fc5cdcfc76234e20d5c6a9e2650e6bd6f3230044783353ba65dde5afb24867af8df4c59189eee67dda25fea
7
- data.tar.gz: 585446ab8b45078fcb666dc9a406516eeac7f715cca90118d5927f5d89acf0cc51056aa75aebed9885c3e5b25f61f9e4baad75869f2d244ab01a359919493b98
6
+ metadata.gz: 36b6893409fad1745593238f9a169623841dc4b55172fd2263f0bba09b3436e8c7f4e6f5ff6fc65bd56233b510daef44df60238189249547205f17087ddd69ab
7
+ data.tar.gz: bddaf3afe21358ed1b9ed73de5585931f4dac9018cc37b30c268aae29cdd7f836ac4f77e4ea419f9268dc4f9f247907996ab2461cd6fc6a44d9e80467b513567
data/lib/config/pagy.rb CHANGED
@@ -1,32 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Pagy initializer file (4.11.0)
3
+ # Pagy initializer file (5.1.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
8
  # Pagy Variables
9
9
  # See https://ddnexus.github.io/pagy/api/pagy#variables
10
- # All the Pagy::VARS are set for all the Pagy instances but can be overridden
10
+ # All the Pagy::DEFAULT are set for all the Pagy instances but can be overridden
11
11
  # per instance by just passing them to Pagy.new or the #pagy controller method
12
12
 
13
13
 
14
14
  # Instance variables
15
15
  # See https://ddnexus.github.io/pagy/api/pagy#instance-variables
16
- # Pagy::VARS[:page] = 1 # default
17
- # Pagy::VARS[:items] = 20 # default
18
- # Pagy::VARS[:outset] = 0 # default
16
+ # Pagy::DEFAULT[:page] = 1 # default
17
+ # Pagy::DEFAULT[:items] = 20 # default
18
+ # Pagy::DEFAULT[:outset] = 0 # default
19
19
 
20
20
 
21
21
  # Other Variables
22
22
  # See https://ddnexus.github.io/pagy/api/pagy#other-variables
23
- # Pagy::VARS[:size] = [1,4,4,1] # default
24
- # Pagy::VARS[:page_param] = :page # default
25
- # Pagy::VARS[:params] = {} # default
26
- # Pagy::VARS[:fragment] = '#fragment' # example
27
- # Pagy::VARS[:link_extra] = 'data-remote="true"' # example
28
- # Pagy::VARS[:i18n_key] = 'pagy.item_name' # default
29
- # Pagy::VARS[:cycle] = true # example
23
+ # Pagy::DEFAULT[:size] = [1,4,4,1] # default
24
+ # Pagy::DEFAULT[:page_param] = :page # default
25
+ # Pagy::DEFAULT[:params] = {} # default
26
+ # Pagy::DEFAULT[:fragment] = '#fragment' # example
27
+ # Pagy::DEFAULT[:link_extra] = 'data-remote="true"' # example
28
+ # Pagy::DEFAULT[:i18n_key] = 'pagy.item_name' # default
29
+ # Pagy::DEFAULT[:cycle] = true # example
30
30
 
31
31
 
32
32
  # Extras
@@ -42,20 +42,43 @@
42
42
  # Countless extra: Paginate without any count, saving one query per rendering
43
43
  # See https://ddnexus.github.io/pagy/extras/countless
44
44
  # require 'pagy/extras/countless'
45
- # Pagy::VARS[:countless_minimal] = false # default (eager loading)
45
+ # Pagy::DEFAULT[:countless_minimal] = false # default (eager loading)
46
46
 
47
47
  # Elasticsearch Rails extra: Paginate `ElasticsearchRails::Results` objects
48
48
  # See https://ddnexus.github.io/pagy/extras/elasticsearch_rails
49
- # default :pagy_search method: change only if you use
50
- # also the searchkick extra that defines the same
51
- # VARS[:elasticsearch_rails_search_method] = :pagy_search
49
+ # default :pagy_search method: change only if you use also
50
+ # the searchkick or meilisearch extra that defines the same
51
+ # Pagy::DEFAULT[:elasticsearch_rails_search_method] = :pagy_search
52
52
  # require 'pagy/extras/elasticsearch_rails'
53
53
 
54
+ # Headers extra: http response headers (and other helpers) useful for API pagination
55
+ # See http://ddnexus.github.io/pagy/extras/headers
56
+ # require 'pagy/extras/headers'
57
+ # Pagy::DEFAULT[:headers] = { page: 'Current-Page',
58
+ # items: 'Page-Items',
59
+ # count: 'Total-Count',
60
+ # pages: 'Total-Pages' } # default
61
+
62
+ # Meilisearch extra: Paginate `Meilisearch` result objects
63
+ # See https://ddnexus.github.io/pagy/extras/meilisearch
64
+ # default :pagy_search method: change only if you use also
65
+ # the elasticsearch_rails or searchkick extra that define the same method
66
+ # Pagy::DEFAULT[:meilisearch_search_method] = :pagy_search
67
+ # require 'pagy/extras/meilisearch'
68
+
69
+ # Metadata extra: Provides the pagination metadata to Javascript frameworks like Vue.js, react.js, etc.
70
+ # See https://ddnexus.github.io/pagy/extras/metadata
71
+ # you must require the shared internal extra (BEFORE the metadata extra) ONLY if you need also the :sequels
72
+ # require 'pagy/extras/shared'
73
+ # require 'pagy/extras/metadata'
74
+ # 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
76
+
54
77
  # Searchkick extra: Paginate `Searchkick::Results` objects
55
78
  # See https://ddnexus.github.io/pagy/extras/searchkick
56
- # default :pagy_search method: change only if you use
57
- # also the elasticsearch_rails extra that defines the same
58
- # VARS[:searchkick_search_method] = :pagy_search
79
+ # default :pagy_search method: change only if you use also
80
+ # the elasticsearch_rails or meilisearch extra that defines the same
81
+ # DEFAULT[:searchkick_search_method] = :pagy_search
59
82
  # require 'pagy/extras/searchkick'
60
83
  # uncomment if you are going to use Searchkick.pagy_search
61
84
  # Searchkick.extend Pagy::Searchkick
@@ -95,47 +118,45 @@
95
118
 
96
119
  # Multi size var used by the *_nav_js helpers
97
120
  # See https://ddnexus.github.io/pagy/extras/navs#steps
98
- # Pagy::VARS[:steps] = { 0 => [2,3,3,2], 540 => [3,5,5,3], 720 => [5,7,7,5] } # example
121
+ # Pagy::DEFAULT[:steps] = { 0 => [2,3,3,2], 540 => [3,5,5,3], 720 => [5,7,7,5] } # example
99
122
 
100
123
 
101
124
  # Feature Extras
102
125
 
103
- # Headers extra: http response headers (and other helpers) useful for API pagination
104
- # See http://ddnexus.github.io/pagy/extras/headers
105
- # require 'pagy/extras/headers'
106
- # Pagy::VARS[:headers] = { page: 'Current-Page', items: 'Page-Items', count: 'Total-Count', pages: 'Total-Pages' } # default
107
-
108
- # Support extra: Extra support for features like: incremental, infinite, auto-scroll pagination
109
- # See https://ddnexus.github.io/pagy/extras/support
110
- # require 'pagy/extras/support'
126
+ # Gearbox extra: Automatically change the number of items per page depending on the page number
127
+ # See https://ddnexus.github.io/pagy/extras/gearbox
128
+ # require 'pagy/extras/gearbox'
129
+ # set to false only if you want to make :gearbox_extra an opt-in variable
130
+ # Pagy::DEFAULT[:gearbox_extra] = false # default true
131
+ # Pagy::DEFAULT[:gearbox_items] = [15, 30, 60, 100] # default
111
132
 
112
133
  # Items extra: Allow the client to request a custom number of items per page with an optional selector UI
113
134
  # See https://ddnexus.github.io/pagy/extras/items
114
135
  # require 'pagy/extras/items'
115
- # Pagy::VARS[:items_param] = :items # default
116
- # Pagy::VARS[:max_items] = 100 # default
117
- # set to false if you want to make :enable_items_extra an opt-in variable
118
- # Pagy::VARS[:enable_items_extra] = false # default true
136
+ # set to false only if you want to make :items_extra an opt-in variable
137
+ # Pagy::DEFAULT[:items_extra] = false # default true
138
+ # Pagy::DEFAULT[:items_param] = :items # default
139
+ # Pagy::DEFAULT[:max_items] = 100 # default
119
140
 
120
141
  # Overflow extra: Allow for easy handling of overflowing pages
121
142
  # See https://ddnexus.github.io/pagy/extras/overflow
122
143
  # require 'pagy/extras/overflow'
123
- # Pagy::VARS[:overflow] = :empty_page # default (other options: :last_page and :exception)
144
+ # Pagy::DEFAULT[:overflow] = :empty_page # default (other options: :last_page and :exception)
124
145
 
125
- # Metadata extra: Provides the pagination metadata to Javascript frameworks like Vue.js, react.js, etc.
126
- # See https://ddnexus.github.io/pagy/extras/metadata
127
- # you must require the shared internal extra (BEFORE the metadata extra) ONLY if you need also the :sequels
128
- # require 'pagy/extras/shared'
129
- # require 'pagy/extras/metadata'
130
- # For performance reason, you should explicitly set ONLY the metadata you use in the frontend
131
- # Pagy::VARS[:metadata] = [:scaffold_url, :count, :page, :prev, :next, :last] # example
146
+ # Support extra: Extra support for features like: incremental, infinite, auto-scroll pagination
147
+ # See https://ddnexus.github.io/pagy/extras/support
148
+ # require 'pagy/extras/support'
132
149
 
133
150
  # Trim extra: Remove the page=1 param from links
134
151
  # See https://ddnexus.github.io/pagy/extras/trim
135
152
  # require 'pagy/extras/trim'
136
- # after requiring it will trim by default
137
- # set to false if you want to make :enable_trim_extra an opt-in variable
138
- # Pagy::VARS[:enable_trim_extra] = false # default true
153
+ # set to false only if you want to make :trim_extra an opt-in variable
154
+ # Pagy::DEFAULT[:trim_extra] = false # default true
155
+
156
+ # Standalone extra: Use pagy in non Rack environment/gem
157
+ # See https://ddnexus.github.io/pagy/extras/standalone
158
+ # require 'pagy/extras/standalone'
159
+ # Pagy::DEFAULT[:url] = 'http://www.example.com/subdir' # optional default
139
160
 
140
161
 
141
162
  # Rails
@@ -173,7 +194,7 @@
173
194
  # {locale: 'es', filepath: 'path/to/pagy-es.yml'},
174
195
  # {locale: 'xyz', # not built-in
175
196
  # filepath: 'path/to/pagy-xyz.yml',
176
- # pluralize: lambda{|count| ... } )
197
+ # pluralize: lambda{ |count| ... } )
177
198
 
178
199
 
179
200
  # I18n extra: uses the standard i18n gem which is ~18x slower using ~10x more memory
@@ -182,4 +203,9 @@
182
203
  # require 'pagy/extras/i18n'
183
204
 
184
205
  # Default i18n key
185
- # Pagy::VARS[:i18n_key] = 'pagy.item_name' # default
206
+ # Pagy::DEFAULT[:i18n_key] = 'pagy.item_name' # default
207
+
208
+
209
+ # When you are done setting your own defaults freeze it,
210
+ # so it will not changed accidentally
211
+ Pagy::DEFAULT.freeze
@@ -1,11 +1,14 @@
1
1
  // See the Pagy documentation: https://ddnexus.github.io/pagy/extras#javascript
2
2
 
3
+ // Container of the whole pagy stuff
3
4
  function Pagy(){}
4
5
 
5
- Pagy.version = '4.11.0'
6
+ Pagy.version = '5.1.1'
6
7
 
8
+ // Used by the waitForMe function
7
9
  Pagy.delay = 100
8
10
 
11
+ // Scan the target for data-pagy-json elements and apply their functions
9
12
  Pagy.init =
10
13
  function(arg) {
11
14
  var target = arg instanceof Event || arg === undefined ? document : arg,
@@ -18,6 +21,7 @@ Pagy.init =
18
21
  }
19
22
  }
20
23
 
24
+ // Power the pagy*_nav_js helpers
21
25
  Pagy.nav =
22
26
  function(pagyEl, tags, sequels, trimParam) {
23
27
  var lastWidth,
@@ -45,14 +49,14 @@ Pagy.nav =
45
49
  else if (typeof(item) === 'string') { html += tags.active.replace(pageREg, item) }
46
50
  }
47
51
  html += tags.after
48
- this.innerHTML = ''
49
52
  this.insertAdjacentHTML('afterbegin', html)
50
53
  lastWidth = width
51
54
  }
52
55
  }.bind(pagyEl)
53
56
  pagyEl.render()
54
- }
57
+ }
55
58
 
59
+ // Power the pagy*_combo_nav_js helpers
56
60
  Pagy.combo_nav =
57
61
  function(pagyEl, page, link, trimParam) {
58
62
  var input = pagyEl.getElementsByTagName('input')[0],
@@ -68,6 +72,7 @@ Pagy.combo_nav =
68
72
  Pagy.addInputEventListeners(input, toPage)
69
73
  }
70
74
 
75
+ // Power the pagy_items_selector_js helper
71
76
  Pagy.items_selector =
72
77
  function(pagyEl, from, link, param) {
73
78
  var input = pagyEl.getElementsByTagName('input')[0],
@@ -75,6 +80,7 @@ Pagy.items_selector =
75
80
  toPage =
76
81
  function() {
77
82
  var items = input.value
83
+ if (items === 0 || items === '') { return }
78
84
  if (current !== items) {
79
85
  var page = Math.max(Math.ceil(from / items), 1),
80
86
  html = link.replace(/__pagy_page__/, page).replace(/__pagy_items__/, items)
@@ -86,6 +92,7 @@ Pagy.items_selector =
86
92
  Pagy.addInputEventListeners(input, toPage)
87
93
  }
88
94
 
95
+ // Utility for input fields
89
96
  Pagy.addInputEventListeners =
90
97
  function(input, toPage) {
91
98
  // select the content on click: easier for typing a number
@@ -96,26 +103,28 @@ Pagy.addInputEventListeners =
96
103
  input.addEventListener('keyup', function(e) { if (e.which === 13) {toPage()} }.bind(this))
97
104
  }
98
105
 
106
+ // Power the trim extra for js helpers
99
107
  Pagy.trim =
100
108
  function(html, param) {
101
109
  var re = new RegExp('[?&]' + param + '=1\\b(?!&)|\\b' + param + '=1&')
102
110
  return html.replace(re, '')
103
111
  }
104
112
 
113
+ // Render all *nav_js helpers
105
114
  Pagy.renderNavs =
106
115
  function() {
107
116
  var navs = document.getElementsByClassName('pagy-njs') // 'pagy-njs' is common to all *nav_js helpers
108
117
  for (var i = 0, len = navs.length; i < len; i++) { navs[i].render() }
109
118
  }
110
119
 
120
+ // Throttle to avoid to fire multiple time the renderNavs on resize
111
121
  Pagy.waitForMe =
112
122
  function() {
113
123
  if (typeof(Pagy.tid) === 'number') { clearTimeout(Pagy.tid) }
114
124
  Pagy.tid = setTimeout(Pagy.renderNavs, Pagy.delay)
115
125
  }
116
126
 
117
-
118
- if (typeof window !== "undefined") {
127
+ // If there is a window object then add the event listener on resize
128
+ if (typeof window !== 'undefined') {
119
129
  window.addEventListener('resize', Pagy.waitForMe, true)
120
130
  }
121
-
data/lib/pagy/backend.rb CHANGED
@@ -2,34 +2,31 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  class Pagy
5
- # Defines a few generic methods to paginate an ORM collection out of the box,
5
+ # Define a few generic methods to paginate an ORM collection out of the box,
6
6
  # or any collection by overriding pagy_get_items and/or pagy_get_vars in your controller
7
-
8
7
  # See also the extras if you need specialized methods to paginate Arrays or other collections
9
-
10
-
11
8
  module Backend
12
- private # the whole module is private so no problem with including it in a controller
9
+ private
13
10
 
14
11
  # Return Pagy object and items
15
- def pagy(collection, vars={})
12
+ def pagy(collection, vars = {})
16
13
  pagy = Pagy.new(pagy_get_vars(collection, vars))
17
- [ pagy, pagy_get_items(collection, pagy) ]
14
+ [pagy, pagy_get_items(collection, pagy)]
18
15
  end
19
16
 
20
17
  # Sub-method called only by #pagy: here for easy customization of variables by overriding
18
+ # You may need to override the count call for non AR collections
21
19
  def pagy_get_vars(collection, vars)
22
- pagy_set_items_from_params(vars) if defined?(UseItemsExtra)
23
- vars[:count] ||= (c = collection.count(:all)).is_a?(Hash) ? c.size : c
24
- vars[:page] ||= params[ vars[:page_param] || VARS[:page_param] ]
20
+ pagy_set_items_from_params(vars) if defined?(ItemsExtra)
21
+ vars[:count] ||= (count = collection.count(:all)).is_a?(Hash) ? count.size : count
22
+ vars[:page] ||= params[vars[:page_param] || DEFAULT[:page_param]]
25
23
  vars
26
24
  end
27
25
 
28
26
  # Sub-method called only by #pagy: here for easy customization of record-extraction by overriding
27
+ # You may need to override this method for collections without offset|limit
29
28
  def pagy_get_items(collection, pagy)
30
- # This should work with ActiveRecord, Sequel, Mongoid...
31
29
  collection.offset(pagy.offset).limit(pagy.items)
32
30
  end
33
-
34
31
  end
35
32
  end
data/lib/pagy/console.rb CHANGED
@@ -1,21 +1,23 @@
1
+ # See Pagy::Console API documentation: https://ddnexus.github.io/pagy/api/console
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require 'pagy' # so you can require just the extra in the console
4
5
  require 'pagy/extras/standalone'
5
6
 
6
7
  class Pagy
7
- # include Pagy::Console in irb/rails console for a ready to use pagy environment
8
+ # Provide a ready to use pagy environment when included in irb/rails console
8
9
  module Console
10
+ # Include Backend, Frontend and set the default URL
9
11
  def self.included(main)
10
12
  main.include(Backend)
11
13
  main.include(Frontend)
12
- VARS[:url] = 'http://www.example.com/subdir'
14
+ DEFAULT[:url] = 'http://www.example.com/subdir'
13
15
  end
14
16
 
17
+ # Require the extras passed as arguments
15
18
  def pagy_extras(*extras)
16
- extras.each {|extra| require "pagy/extras/#{extra}"}
19
+ extras.each { |extra| require "pagy/extras/#{extra}" }
17
20
  puts "Required extras: #{extras.map(&:inspect).join(', ')}"
18
21
  end
19
22
  end
20
-
21
23
  end
@@ -1,38 +1,36 @@
1
+ # See Pagy::Countless API documentation: https://ddnexus.github.io/pagy/api/countless
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require 'pagy'
4
5
 
5
6
  class Pagy
6
-
7
+ # No need to know the count to paginate
7
8
  class Countless < Pagy
8
-
9
- INSTANCE_VARS_MIN = { items: 1, page: 1, outset: 0 }.freeze
10
-
11
9
  # Merge and validate the options, do some simple arithmetic and set a few instance variables
12
- def initialize(vars={}) # rubocop:disable Lint/MissingSuper
13
- @vars = VARS.merge(vars.delete_if{|_,v| v.nil? || v == '' }) # default vars + cleaned vars (can be overridden)
14
- @vars[:fragment] = Pagy.deprecated_var(:anchor, @vars[:anchor], :fragment, @vars[:fragment]) if @vars[:anchor]
15
-
16
- INSTANCE_VARS_MIN.each do |k,min| # validate instance variables
17
- raise VariableError.new(self), "expected :#{k} >= #{min}; got #{@vars[k].inspect}" \
18
- unless @vars[k] && instance_variable_set(:"@#{k}", @vars[k].to_i) >= min
19
- end
20
- @offset = @items * (@page - 1) + @outset # pagination offset + outset (initial offset)
10
+ def initialize(vars = {}) # rubocop:disable Lint/MissingSuper
11
+ normalize_vars(vars)
12
+ setup_vars(page: 1, outset: 0)
13
+ setup_items_var
14
+ @offset = (@items * (@page - 1)) + @outset
21
15
  end
22
16
 
23
- # Finalize the instance variables based on the fetched items
24
- def finalize(fetched)
25
- raise OverflowError.new(self), "page #{@page} got no items" \
26
- if fetched.zero? && @page > 1
17
+ # Finalize the instance variables based on the fetched size
18
+ def finalize(fetched_size)
19
+ raise OverflowError.new(self, :page, "to be < #{@page}") if fetched_size.zero? && @page > 1
27
20
 
28
- @pages = @last = (fetched > @items ? @page + 1 : @page) # set the @pages and @last
29
- @items = fetched if fetched < @items && fetched.positive? # adjust items for last non-empty page
30
- @from = fetched.zero? ? 0 : @offset + 1 - @outset # page begins from item
31
- @to = fetched.zero? ? 0 : @offset + @items - @outset # page ends to item
32
- @prev = (@page-1 unless @page == 1) # nil if no prev page
33
- @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1 # nil if no next page, 1 if :cycle
21
+ @pages = @last = (fetched_size > @items ? @page + 1 : @page)
22
+ @in = [fetched_size, @items].min
23
+ @from = @in.zero? ? 0 : @offset - @outset + 1
24
+ @to = @offset - @outset + @in
25
+ @prev = (@page - 1 unless @page == 1)
26
+ @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
34
27
  self
35
28
  end
36
29
 
30
+ # Override the original series.
31
+ # Return nil if :countless_minimal is enabled
32
+ def series(_size = @vars[:size])
33
+ super unless @vars[:countless_minimal]
34
+ end
37
35
  end
38
36
  end
@@ -1,27 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Pagy
4
-
5
- # generic variable error
4
+ # Generic variable error
6
5
  class VariableError < ArgumentError
7
- attr_reader :pagy
8
-
9
- def initialize(pagy)
10
- super
11
- @pagy = pagy
12
- end
6
+ attr_reader :pagy, :variable, :value
13
7
 
14
- def variable
15
- message =~ /expected :(\w+)/
16
- Regexp.last_match(1)&.to_sym
17
- end
18
-
19
- def value
20
- pagy.vars[variable]
8
+ # Set the variables and prepare the message
9
+ def initialize(pagy, variable, description, value = nil)
10
+ @pagy = pagy
11
+ @variable = variable
12
+ @value = value
13
+ message = +"expected :#{@variable} #{description}"
14
+ message << "; got #{@value.inspect}" if value
15
+ super message
21
16
  end
22
17
  end
23
18
 
24
- # specific overflow error
19
+ # Specific overflow error
25
20
  class OverflowError < VariableError; end
26
21
 
22
+ # I18n configuration error
23
+ class I18nError < StandardError; end
24
+
25
+ # Generic internal error
26
+ class InternalError < StandardError; end
27
27
  end
@@ -2,18 +2,18 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  class Pagy
5
- module Backend
5
+ module ArelExtra
6
6
  private
7
7
 
8
- def pagy_arel(collection, vars={})
8
+ def pagy_arel(collection, vars = {})
9
9
  pagy = Pagy.new(pagy_arel_get_vars(collection, vars))
10
- [ pagy, pagy_get_items(collection, pagy) ]
10
+ [pagy, pagy_get_items(collection, pagy)]
11
11
  end
12
12
 
13
13
  def pagy_arel_get_vars(collection, vars)
14
- pagy_set_items_from_params(vars) if defined?(UseItemsExtra)
14
+ pagy_set_items_from_params(vars) if defined?(ItemsExtra)
15
15
  vars[:count] ||= pagy_arel_count(collection)
16
- vars[:page] ||= params[ vars[:page_param] || VARS[:page_param] ]
16
+ vars[:page] ||= params[vars[:page_param] || DEFAULT[:page_param]]
17
17
  vars
18
18
  end
19
19
 
@@ -27,6 +27,6 @@ class Pagy
27
27
  collection.unscope(:order).limit(1).pluck(sql).first.to_i
28
28
  end
29
29
  end
30
-
31
30
  end
31
+ Backend.prepend ArelExtra
32
32
  end
@@ -3,22 +3,22 @@
3
3
 
4
4
  class Pagy
5
5
  # Add specialized backend methods to paginate array collections
6
- module Backend
6
+ module ArrayExtra
7
7
  private
8
8
 
9
9
  # Return Pagy object and items
10
- def pagy_array(array, vars={})
10
+ def pagy_array(array, vars = {})
11
11
  pagy = Pagy.new(pagy_array_get_vars(array, vars))
12
- [ pagy, array[pagy.offset, pagy.items] ]
12
+ [pagy, array[pagy.offset, pagy.items]]
13
13
  end
14
14
 
15
15
  # Sub-method called only by #pagy_array: here for easy customization of variables by overriding
16
16
  def pagy_array_get_vars(array, vars)
17
- pagy_set_items_from_params(vars) if defined?(UseItemsExtra)
17
+ pagy_set_items_from_params(vars) if defined?(ItemsExtra)
18
18
  vars[:count] ||= array.size
19
- vars[:page] ||= params[ vars[:page_param] || VARS[:page_param] ]
19
+ vars[:page] ||= params[vars[:page_param] || DEFAULT[:page_param]]
20
20
  vars
21
21
  end
22
-
23
22
  end
23
+ Backend.prepend ArrayExtra
24
24
  end
@@ -4,8 +4,9 @@
4
4
  require 'pagy/extras/shared'
5
5
 
6
6
  class Pagy
7
- module Frontend
8
-
7
+ # Frontend modules are specially optimized for performance.
8
+ # The resulting code may not look very elegant, but produces the best benchmarks
9
+ module BootstrapExtra
9
10
  # Pagination for bootstrap: it returns the html with the series of links to the pages
10
11
  def pagy_bootstrap_nav(pagy, pagy_id: nil, link_extra: '')
11
12
  p_id = %( id="#{pagy_id}") if pagy_id
@@ -15,9 +16,13 @@ class Pagy
15
16
  html << pagy_bootstrap_prev_html(pagy, link)
16
17
  pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
17
18
  html << case item
18
- when Integer then %(<li class="page-item">#{link.call item}</li>)
19
- when String then %(<li class="page-item active">#{link.call item}</li>)
20
- when :gap then %(<li class="page-item gap disabled"><a href="#" class="page-link">#{pagy_t 'pagy.nav.gap'}</a></li>)
19
+ when Integer
20
+ %(<li class="page-item">#{link.call item}</li>)
21
+ when String
22
+ %(<li class="page-item active">#{link.call item}</li>)
23
+ when :gap
24
+ %(<li class="page-item gap disabled"><a href="#" class="page-link">#{pagy_t 'pagy.nav.gap'}</a></li>)
25
+ else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
21
26
  end
22
27
  end
23
28
  html << pagy_bootstrap_next_html(pagy, link)
@@ -25,8 +30,7 @@ class Pagy
25
30
  end
26
31
 
27
32
  # Javascript pagination for bootstrap: it returns a nav and a JSON tag used by the Pagy.nav javascript
28
- def pagy_bootstrap_nav_js(pagy, deprecated_id=nil, pagy_id: nil, link_extra: '', steps: nil)
29
- pagy_id = Pagy.deprecated_arg(:id, deprecated_id, :pagy_id, pagy_id) if deprecated_id
33
+ def pagy_bootstrap_nav_js(pagy, pagy_id: nil, link_extra: '', steps: nil)
30
34
  p_id = %( id="#{pagy_id}") if pagy_id
31
35
  link = pagy_link_proc(pagy, link_extra: %(class="page-link" #{link_extra}))
32
36
  tags = { 'before' => %(<ul class="pagination">#{pagy_bootstrap_prev_html pagy, link}),
@@ -35,52 +39,54 @@ class Pagy
35
39
  'gap' => %(<li class="page-item gap disabled"><a href="#" class="page-link">#{pagy_t 'pagy.nav.gap'}</a></li>),
36
40
  'after' => %(#{pagy_bootstrap_next_html pagy, link}</ul>) }
37
41
 
38
- %(<nav#{p_id} class="pagy-njs pagy-bootstrap-nav-js" aria-label="pager" #{pagy_json_attr(pagy, :nav, tags, pagy.sequels(steps))}></nav>)
42
+ %(<nav#{p_id} class="pagy-njs pagy-bootstrap-nav-js" aria-label="pager" #{
43
+ pagy_json_attr(pagy, :nav, tags, pagy.sequels(steps))}></nav>)
39
44
  end
40
45
 
41
46
  # Javascript combo pagination for bootstrap: it returns a nav and a JSON tag used by the Pagy.combo_nav javascript
42
- def pagy_bootstrap_combo_nav_js(pagy, deprecated_id=nil, pagy_id: nil, link_extra: '')
43
- pagy_id = Pagy.deprecated_arg(:id, deprecated_id, :pagy_id, pagy_id) if deprecated_id
47
+ def pagy_bootstrap_combo_nav_js(pagy, pagy_id: nil, link_extra: '')
44
48
  p_id = %( id="#{pagy_id}") if pagy_id
45
49
  link = pagy_link_proc(pagy, link_extra: link_extra)
46
50
  p_page = pagy.page
47
51
  p_pages = pagy.pages
48
- input = %(<input type="number" min="1" max="#{p_pages}" value="#{p_page}" class="text-primary" style="padding: 0; border: none; text-align: center; width: #{p_pages.to_s.length+1}rem;">)
52
+ input = %(<input type="number" min="1" max="#{p_pages}" value="#{
53
+ p_page}" class="text-primary" style="padding: 0; border: none; text-align: center; width: #{
54
+ p_pages.to_s.length + 1}rem;">)
49
55
 
50
56
  %(<nav#{p_id} class="pagy-bootstrap-combo-nav-js pagination" aria-label="pager"><div class="btn-group" role="group" #{
51
- pagy_json_attr pagy, :combo_nav, p_page, pagy_marked_link(link)
52
- }>#{
57
+ pagy_json_attr pagy, :combo_nav, p_page, pagy_marked_link(link)}>#{
53
58
  if (p_prev = pagy.prev)
54
59
  link.call p_prev, pagy_t('pagy.nav.prev'), 'aria-label="previous" class="prev btn btn-primary"'
55
60
  else
56
61
  %(<a class="prev btn btn-primary disabled" href="#">#{pagy_t('pagy.nav.prev')}</a>)
57
62
  end
58
- }<div class="pagy-combo-input btn btn-primary disabled" style="white-space: nowrap;">#{pagy_t 'pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages}</div>#{
63
+ }<div class="pagy-combo-input btn btn-primary disabled" style="white-space: nowrap;">#{
64
+ pagy_t 'pagy.combo_nav_js', page_input: input, count: p_page, pages: p_pages}</div>#{
59
65
  if (p_next = pagy.next)
60
66
  link.call p_next, pagy_t('pagy.nav.next'), 'aria-label="next" class="next btn btn-primary"'
61
67
  else
62
- %(<a class="next btn btn-primary disabled" href="#">#{pagy_t 'pagy.nav.next' }</a>)
68
+ %(<a class="next btn btn-primary disabled" href="#">#{pagy_t 'pagy.nav.next'}</a>)
63
69
  end
64
- }</div></nav>)
70
+ }</div></nav>)
65
71
  end
66
72
 
67
73
  private
68
74
 
69
- def pagy_bootstrap_prev_html(pagy, link)
70
- if (p_prev = pagy.prev)
71
- %(<li class="page-item prev">#{link.call p_prev, pagy_t('pagy.nav.prev'), 'aria-label="previous"'}</li>)
72
- else
73
- %(<li class="page-item prev disabled"><a href="#" class="page-link">#{pagy_t 'pagy.nav.prev'}</a></li>)
74
- end
75
+ def pagy_bootstrap_prev_html(pagy, link)
76
+ if (p_prev = pagy.prev)
77
+ %(<li class="page-item prev">#{link.call p_prev, pagy_t('pagy.nav.prev'), 'aria-label="previous"'}</li>)
78
+ else
79
+ %(<li class="page-item prev disabled"><a href="#" class="page-link">#{pagy_t 'pagy.nav.prev'}</a></li>)
75
80
  end
81
+ end
76
82
 
77
- def pagy_bootstrap_next_html(pagy, link)
78
- if (p_next = pagy.next)
79
- %(<li class="page-item next">#{link.call p_next, pagy_t('pagy.nav.next'), 'aria-label="next"'}</li>)
80
- else
81
- %(<li class="page-item next disabled"><a href="#" class="page-link">#{pagy_t 'pagy.nav.next'}</a></li>)
82
- end
83
+ def pagy_bootstrap_next_html(pagy, link)
84
+ if (p_next = pagy.next)
85
+ %(<li class="page-item next">#{link.call p_next, pagy_t('pagy.nav.next'), 'aria-label="next"'}</li>)
86
+ else
87
+ %(<li class="page-item next disabled"><a href="#" class="page-link">#{pagy_t 'pagy.nav.next'}</a></li>)
83
88
  end
84
-
89
+ end
85
90
  end
91
+ Frontend.prepend BootstrapExtra
86
92
  end