pagy 4.1.0 → 4.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0eec238a32b24a046a7ddaf632f6bfeeb73ef8a2fb0389222b322d50d1b3fd64
4
- data.tar.gz: 9dc1b595e6a6c6b37cb5c1d32080517c383bbbd5d5d1ce023eac384114aeebb7
3
+ metadata.gz: 19e29bbf55102d30e9da7d4e6e3e72b838bd4973451ce861e4724fc1824a6cc8
4
+ data.tar.gz: 483657a52db974186448c72c3dc071dc754855e9d8bf6963886c6c0600cf8516
5
5
  SHA512:
6
- metadata.gz: 9be42486ebe3686f8461d5868427446664b00b7c733dafc4506eca883e280fc71a5c1cbd94fcbe9c8f15e12aa6b6af550e8890f71b835629d45f926d0e850a8b
7
- data.tar.gz: 9563de1d768f284a65ec0ae3f60530e29ea36b62c0455048cefb81fa49c95bae21188beafbc9adc9e16fd7abc902ed1498070942a38847524eb9ffa23b89a75b
6
+ metadata.gz: 41e8776832f9fa255056815fcbae25d066716fd6910cba99eb0a1351807d5e601a1229c1815065a555971f2aa76fca4c9cdee33188ca30e627fb2c7b3afcba64
7
+ data.tar.gz: 23a50e3d270c22a4b12fd12ec0a7543db527a939ddf27da19cf2acab8edfe1f9da1f307ba4adab50775c8d8846728d9a2fad39565257df786ea819980fa67885
data/lib/config/pagy.rb CHANGED
@@ -1,11 +1,34 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
- # Pagy initializer file (4.1.0)
3
+ # Pagy initializer file (4.5.1)
5
4
  # Customize only what you really need and notice that Pagy works also without any of the following lines.
6
5
  # Should you just cherry pick part of this file, please maintain the require-order of the extras
7
6
 
8
7
 
8
+ # Pagy Variables
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
11
+ # per instance by just passing them to Pagy.new or the #pagy controller method
12
+
13
+
14
+ # Instance variables
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
19
+
20
+
21
+ # Other Variables
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
30
+
31
+
9
32
  # Extras
10
33
  # See https://ddnexus.github.io/pagy/extras
11
34
 
@@ -19,7 +42,6 @@
19
42
  # Countless extra: Paginate without any count, saving one query per rendering
20
43
  # See https://ddnexus.github.io/pagy/extras/countless
21
44
  # require 'pagy/extras/countless'
22
- # Pagy::VARS[:cycle] = false # default
23
45
 
24
46
  # Elasticsearch Rails extra: Paginate `ElasticsearchRails::Results` objects
25
47
  # See https://ddnexus.github.io/pagy/extras/elasticsearch_rails
@@ -88,6 +110,8 @@
88
110
  # require 'pagy/extras/items'
89
111
  # Pagy::VARS[:items_param] = :items # default
90
112
  # Pagy::VARS[:max_items] = 100 # default
113
+ # set to false if you want to make :enable_items_extra an opt-in variable
114
+ # Pagy::VARS[:enable_items_extra] = false # default true
91
115
 
92
116
  # Overflow extra: Allow for easy handling of overflowing pages
93
117
  # See https://ddnexus.github.io/pagy/extras/overflow
@@ -105,27 +129,9 @@
105
129
  # Trim extra: Remove the page=1 param from links
106
130
  # See https://ddnexus.github.io/pagy/extras/trim
107
131
  # require 'pagy/extras/trim'
108
-
109
-
110
-
111
- # Pagy Variables
112
- # See https://ddnexus.github.io/pagy/api/pagy#variables
113
- # All the Pagy::VARS are set for all the Pagy instances but can be overridden
114
- # per instance by just passing them to Pagy.new or the #pagy controller method
115
-
116
-
117
- # Instance variables
118
- # See https://ddnexus.github.io/pagy/api/pagy#instance-variables
119
- # Pagy::VARS[:items] = 20 # default
120
-
121
-
122
- # Other Variables
123
- # See https://ddnexus.github.io/pagy/api/pagy#other-variables
124
- # Pagy::VARS[:size] = [1,4,4,1] # default
125
- # Pagy::VARS[:page_param] = :page # default
126
- # Pagy::VARS[:params] = {} # default
127
- # Pagy::VARS[:anchor] = '#anchor' # example
128
- # Pagy::VARS[:link_extra] = 'data-remote="true"' # example
132
+ # after requiring it will trim by default
133
+ # set to false if you want to make :enable_trim_extra an opt-in variable
134
+ # Pagy::VARS[:enable_trim_extra] = false # default true
129
135
 
130
136
 
131
137
  # Rails
@@ -2,105 +2,116 @@
2
2
 
3
3
  function Pagy(){}
4
4
 
5
- Pagy.version = '4.1.0';
5
+ Pagy.version = '4.5.1'
6
6
 
7
- Pagy.init = function(arg){
8
- var target = arg instanceof Event || arg === undefined ? document : arg,
9
- jsonTags = target.getElementsByClassName('pagy-json');
10
- if (target === document) { // reset resize-listeners on page load (#163)
11
- for (var id in Pagy.navResizeListeners) { window.removeEventListener('resize', Pagy.navResizeListeners[id], true) }
12
- Pagy.navResizeListeners = {};
13
- }
14
- for (var i = 0, len = jsonTags.length; i < len; i++) {
15
- var args = JSON.parse(jsonTags[i].innerHTML);
16
- Pagy[args.shift()].apply(null, args);
17
- }
18
- };
7
+ Pagy.delay = 100
19
8
 
20
- Pagy.nav = function(id, tags, sequels, param){
21
- var pagyEl = document.getElementById(id),
22
- lastWidth = undefined,
23
- timeoutId = 0,
24
- pageREg = new RegExp(/__pagy_page__/g),
25
- widths = [],
26
- rendering = function(){ clearTimeout(timeoutId); timeoutId = setTimeout(pagyEl.render, 150) }; // suppress rapid firing rendering
9
+ Pagy.init =
10
+ function(arg) {
11
+ var target = arg instanceof Event || arg === undefined ? document : arg,
12
+ jsonTags = target.getElementsByClassName('pagy-json')
13
+ for (var i = 0, len = jsonTags.length; i < len; i++) {
14
+ var args = JSON.parse(jsonTags[i].innerHTML),
15
+ fname = args.shift()
16
+ args.unshift(jsonTags[i].previousSibling)
17
+ Pagy[fname].apply(null, args)
18
+ }
19
+ }
27
20
 
28
- for (var width in sequels) { widths.push(parseInt(width)) } // fine with sequels structure
29
- widths.sort(function(a, b){return b-a});
21
+ Pagy.nav =
22
+ function(pagyEl, tags, sequels, trimParam) {
23
+ var lastWidth,
24
+ pageREg = new RegExp(/__pagy_page__/g),
25
+ widths = []
26
+ for (var width in sequels) {
27
+ if (sequels.hasOwnProperty(width)) { widths.push(parseInt(width, 10)) }
28
+ }
29
+ widths.sort(function(a, b) { return b - a })
30
30
 
31
- pagyEl.render = function(){
32
- if (this.parentElement.clientWidth === 0) { rendering() }
33
- var width, i, len;
34
- for (i = 0, len = widths.length; i < len; i++) {
35
- if (this.parentElement.clientWidth > widths[i]) { width = widths[i]; break }
36
- }
37
- if (width !== lastWidth) {
38
- var html = tags.before,
39
- series = sequels[width];
40
- for (i = 0, len = series.length; i < len; i++) {
41
- var item = series[i];
42
- if (typeof(param) === 'string' && item === 1) { html += Pagy.trim(tags.link.replace(pageREg, item), param) }
43
- else if (typeof(item) === 'number') { html += tags.link.replace(pageREg, item) }
44
- else if (item === 'gap') { html += tags.gap }
45
- else if (typeof(item) === 'string') { html += tags.active.replace(pageREg, item) }
46
- }
47
- html += tags.after;
48
- this.innerHTML = '';
49
- this.insertAdjacentHTML('afterbegin', html);
50
- lastWidth = width;
51
- }
52
- }.bind(pagyEl);
31
+ pagyEl.render =
32
+ function() {
33
+ var width, i, len
34
+ for (i = 0, len = widths.length; i < len; i++) {
35
+ if (this.parentElement.clientWidth > widths[i]) { width = widths[i]; break }
36
+ }
37
+ if (width !== lastWidth) {
38
+ var html = tags.before,
39
+ series = sequels[width]
40
+ for (i = 0, len = series.length; i < len; i++) {
41
+ var item = series[i]
42
+ if (typeof(trimParam) === 'string' && item === 1) { html += Pagy.trim(tags.link.replace(pageREg, item), trimParam) }
43
+ else if (typeof(item) === 'number') { html += tags.link.replace(pageREg, item) }
44
+ else if (item === 'gap') { html += tags.gap }
45
+ else if (typeof(item) === 'string') { html += tags.active.replace(pageREg, item) }
46
+ }
47
+ html += tags.after
48
+ this.innerHTML = ''
49
+ this.insertAdjacentHTML('afterbegin', html)
50
+ lastWidth = width
51
+ }
52
+ }.bind(pagyEl)
53
+ pagyEl.render()
54
+ }
53
55
 
54
- if (widths.length > 1) {
55
- // refresh the window resize listener (avoiding rendering multiple times)
56
- window.removeEventListener('resize', Pagy.navResizeListeners[id], true); // needed for AJAX init
57
- window.addEventListener('resize', rendering, true);
58
- Pagy.navResizeListeners[id] = rendering;
59
- }
60
- pagyEl.render();
61
- };
56
+ Pagy.combo_nav =
57
+ function(pagyEl, page, link, trimParam) {
58
+ var input = pagyEl.getElementsByTagName('input')[0],
59
+ toPage =
60
+ function() {
61
+ if (page !== input.value) {
62
+ var html = link.replace(/__pagy_page__/, input.value)
63
+ if (typeof (trimParam) === 'string' && input.value === '1') { html = Pagy.trim(html, trimParam) }
64
+ pagyEl.insertAdjacentHTML('afterbegin', html)
65
+ pagyEl.getElementsByTagName('a')[0].click()
66
+ }
67
+ }
68
+ Pagy.addInputEventListeners(input, toPage)
69
+ }
62
70
 
63
- Pagy.combo_nav = function(id, page, link, param){
64
- var pagyEl = document.getElementById(id),
65
- input = pagyEl.getElementsByTagName('input')[0],
66
- go = function(){
67
- if (page !== input.value) {
68
- var html = link.replace(/__pagy_page__/, input.value);
69
- if (typeof(param) === 'string' && input.value === '1') { html = Pagy.trim(html, param) }
70
- pagyEl.insertAdjacentHTML('afterbegin', html);
71
- pagyEl.getElementsByTagName('a')[0].click();
72
- }
73
- };
74
- Pagy.addInputEventListeners(input, go);
75
- };
71
+ Pagy.items_selector =
72
+ function(pagyEl, from, link, param) {
73
+ var input = pagyEl.getElementsByTagName('input')[0],
74
+ current = input.value,
75
+ toPage =
76
+ function() {
77
+ var items = input.value
78
+ if (current !== items) {
79
+ var page = Math.max(Math.ceil(from / items), 1),
80
+ html = link.replace(/__pagy_page__/, page).replace(/__pagy_items__/, items)
81
+ if (typeof (param) === 'string' && page === 1) { html = Pagy.trim(html, param) }
82
+ pagyEl.insertAdjacentHTML('afterbegin', html)
83
+ pagyEl.getElementsByTagName('a')[0].click()
84
+ }
85
+ }
86
+ Pagy.addInputEventListeners(input, toPage)
87
+ }
76
88
 
77
- Pagy.items_selector = function(id, from, link, param){
78
- var pagyEl = document.getElementById(id),
79
- input = pagyEl.getElementsByTagName('input')[0],
80
- current = input.value,
81
- go = function(){
82
- var items = input.value;
83
- if (current !== items) {
84
- var page = Math.max(Math.ceil(from / items),1),
85
- html = link.replace(/__pagy_page__/, page).replace(/__pagy_items__/, items);
86
- if (typeof(param) === 'string' && page === 1){ html = Pagy.trim(html, param) }
87
- pagyEl.insertAdjacentHTML('afterbegin', html);
88
- pagyEl.getElementsByTagName('a')[0].click();
89
- }
90
- };
91
- Pagy.addInputEventListeners(input, go);
92
- };
89
+ Pagy.addInputEventListeners =
90
+ function(input, toPage) {
91
+ // select the content on click: easier for typing a number
92
+ input.addEventListener('click', function() { this.select() })
93
+ // toPage when the input looses focus
94
+ input.addEventListener('focusout', toPage)
95
+ // and when pressing enter inside the input
96
+ input.addEventListener('keyup', function(e) { if (e.which === 13) {toPage()} }.bind(this))
97
+ }
93
98
 
94
- Pagy.addInputEventListeners = function(input, handler){
95
- // select the content on click: easier for typing a number
96
- input.addEventListener('click', function(){ this.select() });
97
- // go when the input looses focus
98
- input.addEventListener('focusout', handler);
99
- // … and when pressing enter inside the input
100
- input.addEventListener('keyup', function(e){ if (e.which === 13) handler() }.bind(this));
101
- };
99
+ Pagy.trim =
100
+ function(html, param) {
101
+ var re = new RegExp('[?&]' + param + '=1\\b(?!&)|\\b' + param + '=1&')
102
+ return html.replace(re, '')
103
+ }
102
104
 
103
- Pagy.trim = function(html, param){
104
- var re = new RegExp('[?&]' + param + '=1\\b(?!&)|\\b' + param + '=1&');
105
- return html.replace(re, '');
106
- };
105
+ Pagy.renderNavs =
106
+ function() {
107
+ var navs = document.getElementsByClassName('pagy-njs') // 'pagy-njs' is common to all *nav_js helpers
108
+ for (var i = 0, len = navs.length; i < len; i++) { navs[i].render() }
109
+ }
110
+
111
+ Pagy.waitForMe =
112
+ function() {
113
+ if (typeof(Pagy.tid) === 'number') { clearTimeout(Pagy.tid) }
114
+ Pagy.tid = setTimeout(Pagy.renderNavs, Pagy.delay)
115
+ }
116
+
117
+ window.addEventListener('resize', Pagy.waitForMe, true)
@@ -1,5 +1,4 @@
1
1
  # See https://ddnexus.github.io/pagy/api/frontend#i18n
2
- # encoding: utf-8
3
2
  # frozen_string_literal: true
4
3
 
5
4
  # this file returns the I18n hash used as default alternative to the i18n gem
@@ -1,18 +1,20 @@
1
- # encoding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
3
  # the whole file will be eval'ed/executed and gc-collected after returning/executing the loader proc
5
4
 
6
5
  # eval: no need for the whole file in memory
7
- plurals, _ = eval(Pagy.root.join('locales', 'utils', 'p11n.rb').read) #rubocop:disable Security/Eval
6
+ plurals, = eval Pagy.root.join('locales', 'utils', 'p11n.rb').read # rubocop:disable Security/Eval
8
7
 
9
8
  # flatten the dictionary file nested keys
10
9
  # convert each value to a simple ruby interpolation proc
11
10
  flatten = lambda do |hash, key=''|
12
11
  hash.each.reduce({}) do |h, (k, v)|
13
- v.is_a?(Hash) \
14
- ? h.merge!(flatten.call(v, "#{key}#{k}."))
15
- : h.merge!(eval %({"#{key}#{k}" => lambda{|vars|"#{v.gsub(/%{[^}]+?}/){|m| "\#{vars[:#{m[2..-2]}]||'#{m}'}" }}"}})) #rubocop:disable Security/Eval
12
+ if v.is_a?(Hash)
13
+ h.merge! flatten.call(v, "#{key}#{k}.")
14
+ else
15
+ code = %({"#{key}#{k}" => lambda{|vars|"#{v.gsub(/%{[^}]+?}/){|m| "\#{vars[:#{m[2..-2]}]||'#{m}'}" }}"}})
16
+ h.merge! eval(code) # rubocop:disable Security/Eval
17
+ end
16
18
  end
17
19
  end
18
20
 
@@ -1,5 +1,4 @@
1
1
  # See https://ddnexus.github.io/pagy/api/frontend#i18n
2
- # encoding: utf-8
3
2
  # frozen_string_literal: true
4
3
 
5
4
  # This file adds support for multiple built-in plualization types.
@@ -18,46 +17,51 @@ from12to14 = [12,13,14].freeze
18
17
  # Each proc may apply to one or more locales below.
19
18
  # Pluralization logic adapted from https://github.com/svenfuchs/rails-i18n
20
19
  p11n = {
21
- one_other: lambda {|n| n == 1 ? 'one' : 'other'}, # default
20
+ one_other: -> (n){ n == 1 ? 'one' : 'other' }, # default
22
21
 
23
22
  east_slavic: lambda do |n|
24
23
  n ||= 0
25
24
  mod10 = n % 10
26
25
  mod100 = n % 100
27
26
 
28
- if mod10 == 1 && mod100 != 11 ; 'one'
29
- elsif from2to4.include?(mod10) && !from12to14.include?(mod100) ; 'few'
30
- elsif mod10 == 0 || from5to9.include?(mod10) || from11to14.include?(mod100) ; 'many'
31
- else 'other'
27
+ case
28
+ when mod10 == 1 && mod100 != 11 then 'one'
29
+ when from2to4.include?(mod10) && !from12to14.include?(mod100) then 'few'
30
+ when mod10 == 0 || from5to9.include?(mod10) || from11to14.include?(mod100) then 'many' # rubocop:disable Style/NumericPredicate
31
+ else 'other'
32
32
  end
33
33
  end,
34
34
 
35
35
  west_slavic: lambda do |n|
36
- if n == 1 ; 'one'
37
- elsif [2, 3, 4].include?(n) ; 'few'
38
- else ; 'other'
39
- end
36
+ case n
37
+ when 1 then 'one'
38
+ when 2, 3, 4 then 'few'
39
+ else 'other'
40
+ end
40
41
  end,
41
42
 
42
43
  one_two_other: lambda do |n|
43
- if n == 1 ; 'one'
44
- elsif n == 2 ; 'two'
45
- else 'other'
44
+ case n
45
+ when 1 then 'one'
46
+ when 2 then 'two'
47
+ else 'other'
46
48
  end
47
49
  end,
48
50
 
49
- one_upto_two_other: lambda {|n| n && n >= 0 && n < 2 ? 'one' : 'other'},
51
+ one_upto_two_other: -> (n){ n && n >= 0 && n < 2 ? 'one' : 'other' },
50
52
 
51
- other: Proc.new { 'other' },
53
+ other: -> (*){ 'other' },
52
54
 
53
55
  polish: lambda do |n|
54
56
  n ||= 0
55
- mod10 = n % 10
57
+ mod10 = n % 10
56
58
  mod100 = n % 100
57
- if n == 1 ; 'one'
58
- elsif from2to4.include?(mod10) && !from12to14.include?(mod100) ; 'few'
59
- elsif (from0to1 + from5to9).include?(mod10) || from12to14.include?(mod100) ; 'many'
60
- else 'other'
59
+
60
+ case
61
+ when n == 1 then 'one'
62
+ when from2to4.include?(mod10) && !from12to14.include?(mod100) then 'few'
63
+ when (from0to1 + from5to9).include?(mod10) || from12to14.include?(mod100) then 'many'
64
+ else 'other'
61
65
  end
62
66
  end
63
67
  }
data/lib/pagy.rb CHANGED
@@ -1,52 +1,76 @@
1
1
  # See Pagy API documentation: https://ddnexus.github.io/pagy/api/pagy
2
- # encoding: utf-8
3
2
  # frozen_string_literal: true
4
3
 
5
4
  require 'pathname'
6
5
 
7
- class Pagy ; VERSION = '4.1.0'
6
+ # main class
7
+ class Pagy
8
+ VERSION = '4.5.1'
8
9
 
9
10
  # Root pathname to get the path of Pagy files like templates or dictionaries
10
- def self.root = @root ||= Pathname.new(__FILE__).dirname.freeze
11
+ def self.root
12
+ @root ||= Pathname.new(__dir__).freeze
13
+ end
11
14
 
12
15
  # default vars
13
- VARS = { page:1, items:20, outset:0, size:[1,4,4,1], page_param: :page, params:{}, anchor:'', link_extra:'', i18n_key:'pagy.item_name', cycle:false }
16
+ VARS = { page: 1, items: 20, outset: 0, size: [1, 4, 4, 1], page_param: :page, # rubocop:disable Style/MutableConstant
17
+ params: {}, fragment: '', link_extra: '', i18n_key: 'pagy.item_name', cycle: false }
14
18
 
15
19
  attr_reader :count, :page, :items, :vars, :pages, :last, :offset, :from, :to, :prev, :next
16
20
 
21
+ INSTANCE_VARS_MIN = { count: 0, items: 1, page: 1, outset: 0 }.freeze
22
+
17
23
  # Merge and validate the options, do some simple arithmetic and set the instance variables
18
24
  def initialize(vars)
19
- @vars = VARS.merge(vars.delete_if{|_,v| v.nil? || v == '' }) # default vars + cleaned vars
20
- { count:0, items:1, outset:0, page:1 }.each do |k,min| # validate instance variables
21
- (@vars[k] && instance_variable_set(:"@#{k}", @vars[k].to_i) >= min) \
22
- or raise(VariableError.new(self), "expected :#{k} >= #{min}; got #{@vars[k].inspect}")
25
+ @vars = VARS.merge( vars.delete_if{|k,v| VARS.key?(k) && (v.nil? || v == '') } )
26
+ @vars[:fragment] = deprecated_var(:anchor, @vars[:anchor], :fragment, @vars[:fragment]) if @vars[:anchor]
27
+
28
+ INSTANCE_VARS_MIN.each do |name,min|
29
+ raise VariableError.new(self), "expected :#{name} >= #{min}; got #{@vars[name].inspect}" \
30
+ unless @vars[name] && instance_variable_set(:"@#{name}", @vars[name].to_i) >= min
23
31
  end
24
- @pages = @last = [(@count.to_f / @items).ceil, 1].max # cardinal and ordinal meanings
25
- @page <= @last or raise(OverflowError.new(self), "expected :page in 1..#{@last}; got #{@page.inspect}")
26
- @offset = @items * (@page - 1) + @outset # pagination offset + outset (initial offset)
27
- @items = @count - ((@pages-1) * @items) if @page == @last && @count > 0 # adjust items for last non-empty page
28
- @from = @count == 0 ? 0 : @offset+1 - @outset # page begins from item
29
- @to = @count == 0 ? 0 : @offset + @items - @outset # page ends to item
30
- @prev = (@page-1 unless @page == 1) # nil if no prev page
31
- @next = @page == @last ? (1 if @vars[:cycle]) : @page+1 # nil if no next page, 1 if :cycle
32
+ @pages = @last = [(@count.to_f / @items).ceil, 1].max
33
+ raise OverflowError.new(self), "expected :page in 1..#{@last}; got #{@page.inspect}" \
34
+ if @page > @last
35
+
36
+ @offset = @items * (@page - 1) + @outset
37
+ @items = @count - ((@pages - 1) * @items) if @page == @last && @count.positive?
38
+ @from = @count.zero? ? 0 : @offset + 1 - @outset
39
+ @to = @count.zero? ? 0 : @offset + @items - @outset
40
+ @prev = (@page - 1 unless @page == 1)
41
+ @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1
32
42
  end
33
43
 
34
44
  # Return the array of page numbers and :gap items e.g. [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
35
45
  def series(size=@vars[:size])
36
- (series = []) and size.empty? and return series
37
- 4.times{|i| (size[i]>=0 rescue nil) or raise(VariableError.new(self), "expected 4 items >= 0 in :size; got #{size.inspect}")}
38
- [*0..size[0], *@page-size[1]..@page+size[2], *@last-size[3]+1..@last+1].sort!.each_cons(2) do |a, b|
39
- if a<0 || a==b || a>@last; next # skip out of range and duplicates
40
- elsif a+1 == b; series.push(a) # no gap -> no additions
41
- elsif a+2 == b; series.push(a, a+1) # 1 page gap -> fill with missing page
42
- else series.push(a, :gap) # n page gap -> add gap
43
- end # skip the end boundary (last+1)
44
- end # shift the start boundary (0) and
45
- series.shift; series[series.index(@page)] = @page.to_s; series # convert the current page to String
46
+ return [] if size.empty?
47
+ raise VariableError.new(self), "expected 4 items >= 0 in :size; got #{size.inspect}" \
48
+ unless size.size == 4 && size.all?{ |num| !num.negative? rescue false } # rubocop:disable Style/RescueModifier
49
+ # This algorithm is up to ~5x faster and ~2.3x lighter than the previous one (pagy < 4.3)
50
+ left_gap_start = 1 + size[0]
51
+ left_gap_end = @page - size[1] - 1
52
+ right_gap_start = @page + size[2] + 1
53
+ right_gap_end = @last - size[3]
54
+ left_gap_end = right_gap_end if left_gap_end > right_gap_end
55
+ right_gap_start = left_gap_start if left_gap_start > right_gap_start
56
+ series = []
57
+ start = 1
58
+ if (left_gap_end - left_gap_start).positive?
59
+ series.push(*start..(left_gap_start - 1), :gap)
60
+ start = left_gap_end + 1
61
+ end
62
+ if (right_gap_end - right_gap_start).positive?
63
+ series.push(*start..(right_gap_start - 1), :gap)
64
+ start = right_gap_end + 1
65
+ end
66
+ series.push(*start..@last)
67
+ series[series.index(@page)] = @page.to_s
68
+ series
46
69
  end
47
70
 
48
71
  end
49
72
 
73
+ require 'pagy/deprecation'
50
74
  require 'pagy/backend'
51
75
  require 'pagy/frontend'
52
76
  require 'pagy/exceptions'