pagy 0.7.2 → 0.8.0
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 +4 -4
- data/lib/pagy.rb +6 -6
- data/lib/pagy/backend.rb +7 -6
- data/lib/pagy/extras/array.rb +20 -0
- data/lib/pagy/extras/bootstrap.rb +26 -0
- data/lib/pagy/extras/compact.rb +51 -0
- data/lib/pagy/extras/i18n.rb +16 -0
- data/lib/pagy/extras/initializer_example.rb +55 -0
- data/lib/pagy/extras/javascripts/pagy-compact.js +15 -0
- data/lib/pagy/extras/javascripts/pagy-responsive.js +24 -0
- data/lib/pagy/extras/responsive.rb +73 -0
- data/lib/{templates → pagy/extras/templates}/nav.html.erb +0 -0
- data/lib/{templates → pagy/extras/templates}/nav.html.haml +0 -0
- data/lib/{templates → pagy/extras/templates}/nav.html.slim +0 -0
- data/lib/pagy/extras/templates/nav_bootstrap.html.erb +24 -0
- data/lib/pagy/extras/templates/nav_bootstrap.html.haml +34 -0
- data/lib/pagy/extras/templates/nav_bootstrap.html.slim +34 -0
- data/lib/pagy/frontend.rb +20 -24
- data/pagy.gemspec +8 -0
- metadata +34 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ae2667539ba0f1f518150c750faee613c5a47a3dc2154d9fc5ccbdd243891fbf
|
4
|
+
data.tar.gz: 4eea6d2bfaf058897bcc233f93ee7c8c43d29f139c374ed9e6fb5685f6e03258
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 241dc6c9f6b1bcb69edf5294112f915866709ed338947f30ab96ff3be79d0ed677f4a0d41fd08d9ed05495cf661d054b52effaaa948120aa8fe9ffbc6b638ae6
|
7
|
+
data.tar.gz: f90c99e9c32cc9e27314555f8f531eb598be43b4c26bb3038506127b73b918f95132b84fa3db688e85003e8addae6314cd55a274743a8f95d85cf6349e670f99
|
data/lib/pagy.rb
CHANGED
@@ -2,10 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'pathname'
|
4
4
|
|
5
|
-
class Pagy ; VERSION = '0.
|
6
|
-
|
7
|
-
autoload :Backend, 'pagy/backend'
|
8
|
-
autoload :Frontend, 'pagy/frontend'
|
5
|
+
class Pagy ; VERSION = '0.8.0'
|
9
6
|
|
10
7
|
class OutOfRangeError < StandardError; end
|
11
8
|
|
@@ -13,7 +10,7 @@ class Pagy ; VERSION = '0.7.2'
|
|
13
10
|
def self.root; Pathname.new(__FILE__).dirname end
|
14
11
|
|
15
12
|
# default core vars
|
16
|
-
VARS = { page:1, items:20, outset:0, size:[1,4,4,1] }
|
13
|
+
VARS = { page:1, items:20, outset:0, size:[1,4,4,1], page_param: :page }
|
17
14
|
|
18
15
|
# default I18n vars
|
19
16
|
zero_one = [:zero, :one] ; I18N = { file: Pagy.root.join('locales', 'pagy.yml').to_s, plurals: -> (c) {(zero_one[c] || :other).to_s.freeze} }
|
@@ -22,7 +19,7 @@ class Pagy ; VERSION = '0.7.2'
|
|
22
19
|
|
23
20
|
# merge and validate the options, do some simple aritmetic and set the instance variables
|
24
21
|
def initialize(vars)
|
25
|
-
@vars = VARS.merge(vars.delete_if{|
|
22
|
+
@vars = VARS.merge(vars.delete_if{|_,v| v.nil? || v == '' }) # default vars + cleaned instance vars
|
26
23
|
{ count:0, items:1, outset:0, page:1 }.each do |k,min| # validate core variables
|
27
24
|
(@vars[k] && instance_variable_set(:"@#{k}", @vars.delete(k).to_i) >= min) \
|
28
25
|
or raise(ArgumentError, "expected :#{k} >= #{min}; got #{instance_variable_get(:"@#{k}").inspect}")
|
@@ -52,3 +49,6 @@ class Pagy ; VERSION = '0.7.2'
|
|
52
49
|
end
|
53
50
|
|
54
51
|
end
|
52
|
+
|
53
|
+
require 'pagy/backend'
|
54
|
+
require 'pagy/frontend'
|
data/lib/pagy/backend.rb
CHANGED
@@ -4,21 +4,22 @@ class Pagy
|
|
4
4
|
# Defines a few generic methods to paginate a ORM collection out of the box,
|
5
5
|
# or any collection by overriding pagy_get_items in your controller
|
6
6
|
|
7
|
-
# See also the
|
7
|
+
# See also the extras if you need specialized methods to paginate
|
8
8
|
# Arrays, ORM, and other TBD collections
|
9
9
|
|
10
10
|
module Backend ; private # the whole module is private so no problem with including it in a controller
|
11
11
|
|
12
12
|
# return pagy object and items
|
13
|
-
def pagy(collection, vars=
|
14
|
-
pagy = Pagy.new(
|
13
|
+
def pagy(collection, vars={})
|
14
|
+
pagy = Pagy.new(pagy_get_vars(collection, vars))
|
15
15
|
return pagy, pagy_get_items(collection, pagy)
|
16
16
|
end
|
17
17
|
|
18
18
|
# sub-method called only by #pagy: here for easy customization of variables by overriding
|
19
|
-
def pagy_get_vars(collection)
|
20
|
-
# return the variables to initialize the pagy object
|
21
|
-
{ count: collection.count,
|
19
|
+
def pagy_get_vars(collection, vars)
|
20
|
+
# return the merged variables to initialize the pagy object
|
21
|
+
{ count: collection.count,
|
22
|
+
page: params[vars[:page_param]||VARS[:page_param]] }.merge!(vars)
|
22
23
|
end
|
23
24
|
|
24
25
|
# sub-method called only by #pagy: here for easy customization of record-extraction by overriding
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# See the Pagy Extras documentation: https://ddnexus.github.io/pagy/extras
|
2
|
+
|
3
|
+
class Pagy
|
4
|
+
# Add specialized backend methods to paginate array collections
|
5
|
+
module Backend ; private
|
6
|
+
|
7
|
+
# return pagy object and items
|
8
|
+
def pagy_array(array, vars={})
|
9
|
+
pagy = Pagy.new(pagy_array_get_vars(array, vars))
|
10
|
+
return pagy, array[pagy.offset, pagy.items]
|
11
|
+
end
|
12
|
+
|
13
|
+
def pagy_array_get_vars(array, vars)
|
14
|
+
# return the merged variables to initialize the pagy object
|
15
|
+
{ count: array.count,
|
16
|
+
page: params[vars[:page_param]||VARS[:page_param]] }.merge!(vars)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# See the Pagy Extras documentation: https://ddnexus.github.io/pagy/extras
|
2
|
+
|
3
|
+
class Pagy
|
4
|
+
# Add nav helper for bootstrap pagination
|
5
|
+
module Frontend
|
6
|
+
|
7
|
+
# Pagination for bootstrap: it returns the html with the series of links to the pages
|
8
|
+
def pagy_nav_bootstrap(pagy)
|
9
|
+
tags = ''; link = pagy_link_proc(pagy, 'class="page-link"'.freeze)
|
10
|
+
|
11
|
+
tags << (pagy.prev ? %(<li class="page-item prev">#{link.call pagy.prev, pagy_t('pagy.nav.prev'.freeze), 'aria-label="previous"'.freeze}</li>)
|
12
|
+
: %(<li class="page-item prev disabled"><a href="#" class="page-link">#{pagy_t('pagy.nav.prev'.freeze)}</a></li>))
|
13
|
+
pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
|
14
|
+
tags << if item.is_a?(Integer); %(<li class="page-item">#{link.call item}</li>) # page link
|
15
|
+
elsif item.is_a?(String) ; %(<li class="page-item active">#{link.call item}</li>) # active page
|
16
|
+
elsif item == :gap ; %(<li class="page-item gap disabled"><a href="#" class="page-link">#{pagy_t('pagy.nav.gap'.freeze)}</a></li>) # page gap
|
17
|
+
end
|
18
|
+
end
|
19
|
+
tags << (pagy.next ? %(<li class="page-item next">#{link.call pagy.next, pagy_t('pagy.nav.next'.freeze), 'aria-label="next"'.freeze}</li>)
|
20
|
+
: %(<li class="page-item next disabled"><a href="#" class="page-link">#{pagy_t('pagy.nav.next'.freeze)}</a></li>))
|
21
|
+
%(<nav class="pagy-nav-boostrap pagination" role="navigation" aria-label="pager"><ul class="pagination">#{tags}</ul></nav>)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# See the Pagy Extras documentation: https://ddnexus.github.io/pagy/extras
|
2
|
+
|
3
|
+
class Pagy
|
4
|
+
# Add nav helpers for compact pagination
|
5
|
+
module Frontend
|
6
|
+
|
7
|
+
# Generic compact pagination: it returns the html with the series of links to the pages
|
8
|
+
# we use a numeric input tag to set the page and the PagyCompact javascript to navigate
|
9
|
+
def pagy_nav_compact(pagy, id=caller(1,1)[0].hash)
|
10
|
+
tags = ''; link = pagy_link_proc(pagy)
|
11
|
+
|
12
|
+
tags << %(<nav id="pagy-nav-#{id}" class="pagy-nav-compact pagination" role="navigation" aria-label="pager">)
|
13
|
+
|
14
|
+
tags << link.call(MARKER, '', %(style="display: none;" ))
|
15
|
+
tags << (pagy.prev ? %(<span class="page prev">#{link.call pagy.prev, pagy_t('pagy.nav.prev'.freeze), 'aria-label="previous"'.freeze}</span> )
|
16
|
+
: %(<span class="page prev disabled">#{pagy_t('pagy.nav.prev'.freeze)}</span> ))
|
17
|
+
|
18
|
+
input = %(<input type="number" min="1" max="#{pagy.last}" value="#{pagy.page}" style="padding: 0; text-align: center; width: #{pagy.pages.to_s.length+1}rem;">)
|
19
|
+
tags << %(<span class="pagy-compact-input" style="margin: 0 0.6rem;">#{pagy_t('pagy.compact.page'.freeze)} #{input} #{pagy_t('pagy.compact.of'.freeze)} #{pagy.pages}</span> )
|
20
|
+
|
21
|
+
tags << (pagy.next ? %(<span class="page next">#{link.call pagy.next, pagy_t('pagy.nav.next'.freeze), 'aria-label="next"'.freeze}</span>)
|
22
|
+
: %(<span class="page next disabled">#{pagy_t('pagy.nav.next'.freeze)}</span>))
|
23
|
+
|
24
|
+
tags << %(</nav><script>PagyCompact('#{id}', '#{MARKER}', '#{pagy.page}');</script>)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Compact pagination for bootstrap: it returns the html with the series of links to the pages
|
28
|
+
# we use a numeric input tag to set the page and the PagyCompact javascript to navigate
|
29
|
+
def pagy_nav_bootstrap_compact(pagy, id=caller(1,1)[0].hash)
|
30
|
+
tags = ''; link = pagy_link_proc(pagy)
|
31
|
+
|
32
|
+
tags << %(<nav id="pagy-nav-#{id}" class="pagy-nav-bootstrap-compact pagination" role="navigation" aria-label="pager">)
|
33
|
+
|
34
|
+
tags << link.call(MARKER, '', %(style="display: none;" ))
|
35
|
+
|
36
|
+
tags << %(<div class="btn-group" role="group">)
|
37
|
+
tags << (pagy.prev ? link.call(pagy.prev, pagy_t('pagy.nav.prev'.freeze), 'aria-label="previous" class="prev btn btn-primary"'.freeze)
|
38
|
+
: %(<a class="prev btn btn-primary disabled" href="#">#{pagy_t('pagy.nav.prev'.freeze)}</a>))
|
39
|
+
|
40
|
+
input = %(<input type="number" min="1" max="#{pagy.last}" value="#{pagy.page}" style="padding: 0; border: none; text-align: center; width: #{pagy.pages.to_s.length+1}rem;">)
|
41
|
+
tags << %(<div class="pagy-compact-input btn btn-primary disabled">#{pagy_t('pagy.compact.page'.freeze)} #{input} #{pagy_t('pagy.compact.of'.freeze)} #{pagy.pages}</div>)
|
42
|
+
|
43
|
+
tags << (pagy.next ? link.call(pagy.next, pagy_t('pagy.nav.next'.freeze), 'aria-label="next" class="next btn btn-primary"'.freeze)
|
44
|
+
: %(<a class="next btn btn-primary disabled" href="#">#{pagy_t('pagy.nav.next'.freeze)}</a>))
|
45
|
+
|
46
|
+
tags << %(</div></nav><script>PagyCompact('#{id}', '#{MARKER}', '#{pagy.page}');</script>)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# See the Pagy Extras documentation: https://ddnexus.github.io/pagy/extras
|
2
|
+
|
3
|
+
class Pagy
|
4
|
+
# Use ::I18n gem
|
5
|
+
module Frontend
|
6
|
+
|
7
|
+
::I18n.load_path << I18N[:file]
|
8
|
+
|
9
|
+
# overrides the built-in pagy_t
|
10
|
+
def pagy_t(*args)
|
11
|
+
I18n.t(*args)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# Example of initializer file
|
2
|
+
# Customize only what you really need but notice that Pagy works also without any of the following lines.
|
3
|
+
|
4
|
+
|
5
|
+
# Extras
|
6
|
+
# See https://ddnexus.github.io/pagy/extras
|
7
|
+
|
8
|
+
# Array: Paginate arrays efficiently avoiding expensive array-wrapping and wihout overriding
|
9
|
+
# See https://ddnexus.github.io/pagy/extras/array
|
10
|
+
# require 'pagy/extras/array'
|
11
|
+
|
12
|
+
# Bootstrap: Nav helper and templates for Bootstrap pagination
|
13
|
+
# See https://ddnexus.github.io/pagy/extras/bootstrap
|
14
|
+
# require 'pagy/extras/bootstrap'
|
15
|
+
|
16
|
+
# Compact: An alternative UI that combines the pagination with the nav info in one compact element
|
17
|
+
# See https://ddnexus.github.io/pagy/extras/compact
|
18
|
+
# require 'pagy/extras/compact'
|
19
|
+
|
20
|
+
# I18n: Uses the `I18n` gem instead of the pagy implementation
|
21
|
+
# See https://ddnexus.github.io/pagy/extras/i18n
|
22
|
+
# require 'pagy/extras/i18n'
|
23
|
+
|
24
|
+
# Responsive: On resize, the number of page links will adapt in real-time to the available window or container width
|
25
|
+
# See https://ddnexus.github.io/pagy/extras/responsive
|
26
|
+
# require 'pagy/extras/responsive'
|
27
|
+
|
28
|
+
|
29
|
+
# Pagy Variables
|
30
|
+
# All the Pagy::VARS here are set for all the pagy instances but can be
|
31
|
+
# overridden by just passing them to Pagy.new or the pagy controller method
|
32
|
+
|
33
|
+
# Core variables (See https://ddnexus.github.io/pagy/api/pagy#core-variables)
|
34
|
+
# Pagy::VARS[:items] = 20 # default
|
35
|
+
|
36
|
+
# Non Core Variables (See https://ddnexus.github.io/pagy/api/pagy#non-core-variables)
|
37
|
+
# Pagy::VARS[:size] = [1,4,4,1] # default
|
38
|
+
# Pagy::Vars[:page_param] = :page # default
|
39
|
+
# Pagy::VARS[:link_extra] = 'data-remote="true"' # example
|
40
|
+
# Pagy::VARS[:item_path] = 'activerecord.models.product' # example
|
41
|
+
|
42
|
+
# Extras Non Core Variables
|
43
|
+
# See https://ddnexus.github.io/pagy/extras/responsive#breakpoints
|
44
|
+
# Pagy::VARS[:breakpoints] = { 0 => [1,2,2,1], 350 => [2,3,3,2], 550 => [3,4,4,3] } # example of width/size pairs
|
45
|
+
|
46
|
+
|
47
|
+
# I18n Variables
|
48
|
+
# See https://ddnexus.github.io/pagy/api/frontend#pagy_tpath-vars
|
49
|
+
# Pagy::I18N[:file] = Pagy.root.join('locales', 'pagy.yml').to_s # default
|
50
|
+
# Pagy::I18N[:plurals] = -> (c) {([:zero, :one][c] || :other).to_s # default
|
51
|
+
|
52
|
+
|
53
|
+
# Rails: extras assets path required by compact or responsive extras
|
54
|
+
# See https://ddnexus.github.io/pagy/extras/compact and https://ddnexus.github.io/pagy/extras/responsive
|
55
|
+
# Rails.application.config.assets.paths << Pagy.root.join('pagy', 'extras', 'javascripts')
|
@@ -0,0 +1,15 @@
|
|
1
|
+
function PagyCompact(id, marker, page){
|
2
|
+
var pagyNav = document.getElementById('pagy-nav-'+id),
|
3
|
+
input = pagyNav.getElementsByTagName('input')[0],
|
4
|
+
link = pagyNav.getElementsByTagName('a')[0];
|
5
|
+
|
6
|
+
this.go = function(){
|
7
|
+
if (page !== input.value) {
|
8
|
+
var href = link.getAttribute('href').replace(marker, input.value);
|
9
|
+
link.setAttribute('href', href);
|
10
|
+
link.click();
|
11
|
+
}
|
12
|
+
};
|
13
|
+
|
14
|
+
input.addEventListener("focusout", this.go);
|
15
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
function PagyResponsive(id, items, widths, series){
|
2
|
+
var pagyNav = document.getElementById('pagy-nav-'+id),
|
3
|
+
pagyBox = pagyNav.firstChild || pagyNav,
|
4
|
+
pagyParent = pagyNav.parentElement,
|
5
|
+
lastWidth = undefined;
|
6
|
+
|
7
|
+
this.render = function(){
|
8
|
+
var parentWidth = parseInt(pagyParent.clientWidth),
|
9
|
+
width = widths.find(function(w){return parentWidth > w});
|
10
|
+
if (width !== lastWidth) {
|
11
|
+
while (pagyBox.firstChild) { pagyBox.removeChild(pagyBox.firstChild) }
|
12
|
+
var tags = items['prev'];
|
13
|
+
series[width].forEach(function(item){tags += items[item]});
|
14
|
+
tags += items['next'];
|
15
|
+
pagyBox.insertAdjacentHTML('beforeend', tags);
|
16
|
+
lastWidth = width;
|
17
|
+
}
|
18
|
+
};
|
19
|
+
|
20
|
+
if (window.attachEvent) { window.attachEvent('onresize', this.render) }
|
21
|
+
else if (window.addEventListener) { window.addEventListener('resize', this.render, true) }
|
22
|
+
|
23
|
+
this.render();
|
24
|
+
};
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# See the Pagy Extras documentation: https://ddnexus.github.io/pagy/extras
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
class Pagy
|
6
|
+
|
7
|
+
# default :breakpoints
|
8
|
+
VARS[:breakpoints] = { 0 => [1,4,4,1] }
|
9
|
+
|
10
|
+
# Helper for building the page_nav with javascript. For example:
|
11
|
+
# with an object like:
|
12
|
+
# Pagy.new count:1000, page: 20, breakpoints: {0 => [1,2,2,1], 350 => [2,3,3,2], 550 => [3,4,4,3]}
|
13
|
+
# it returns something like:
|
14
|
+
# { :items => [1, :gap, 18, 19, "20", 21, 22, 50, 2, 17, 23, 49, 3, 16, 24, 48],
|
15
|
+
# :series => { 0 =>[1, :gap, 18, 19, "20", 21, 22, :gap, 50],
|
16
|
+
# 350 =>[1, 2, :gap, 17, 18, 19, "20", 21, 22, 23, :gap, 49, 50],
|
17
|
+
# 550 =>[1, 2, 3, :gap, 16, 17, 18, 19, "20", 21, 22, 23, 24, :gap, 48, 49, 50] },
|
18
|
+
# :widths => [550, 350, 0] }
|
19
|
+
# where :items is the unordered array union of all the page numbers for all sizes (passed to the PagyResponsive javascript function)
|
20
|
+
# :series is the hash of the series keyed by width (used by the *_responsive helpers to create the JSON string)
|
21
|
+
# :widths is the desc-ordered array of widths (passed to the PagyResponsive javascript function)
|
22
|
+
def responsive
|
23
|
+
@responsive ||= {items: [], series: {}, widths:[]}.tap do |r|
|
24
|
+
@vars[:breakpoints].key?(0) || raise(ArgumentError, "expected :breakpoints to contain the 0 size; got #{@vars[:breakpoint].inspect}")
|
25
|
+
@vars[:breakpoints].each {|width, size| r[:items] |= r[:series][width] = series(size)}
|
26
|
+
r[:widths] = r[:series].keys.sort!{|a,b| b <=> a}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Add nav helpers for responsive pagination
|
31
|
+
module Frontend
|
32
|
+
|
33
|
+
# Generic responsive pagination: it returns the html with the series of links to the pages
|
34
|
+
# we build the tags as a json object string and render them with the PagyResponsive javascript
|
35
|
+
def pagy_nav_responsive(pagy, id=caller(1,1)[0].hash)
|
36
|
+
tags = '{'; link = pagy_link_proc(pagy); responsive = pagy.responsive
|
37
|
+
|
38
|
+
tags << (pagy.prev ? %('prev':'<span class="page prev">#{link.call pagy.prev, pagy_t('pagy.nav.prev'.freeze), 'aria-label="previous"'.freeze}</span> ',)
|
39
|
+
: %('prev':'<span class="page prev disabled">#{pagy_t('pagy.nav.prev'.freeze)}</span> ',))
|
40
|
+
responsive[:items].each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
|
41
|
+
tags << if item.is_a?(Integer); %('#{item}':'<span class="page">#{link.call item}</span> ',) # page link
|
42
|
+
elsif item.is_a?(String) ; %('#{item}':'<span class="page active">#{item}</span> ',) # current page
|
43
|
+
elsif item == :gap ; %('#{item}':'<span class="page gap">#{pagy_t('pagy.nav.gap'.freeze)}</span> ',) # page gap
|
44
|
+
end
|
45
|
+
end
|
46
|
+
tags << (pagy.next ? %('next':'<span class="page next">#{link.call pagy.next, pagy_t('pagy.nav.next'.freeze), 'aria-label="next"'.freeze}</span>'})
|
47
|
+
: %('next':'<span class="page next disabled">#{pagy_t('pagy.nav.next'.freeze)}</span>'}))
|
48
|
+
script = %(<script>PagyResponsive('#{id}', #{tags}, #{responsive[:widths].to_json}, #{responsive[:series].to_json});</script>)
|
49
|
+
%(<nav id="pagy-nav-#{id}" class="pagy-nav-responsive pagination" role="navigation" aria-label="pager"></nav>#{script})
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# Responsive pagination for bootstrap: it returns the html with the series of links to the pages
|
54
|
+
# we build the tags as a json object string and render them with the PagyResponsive javascript
|
55
|
+
def pagy_nav_bootstrap_responsive(pagy, id=caller(1,1)[0].hash)
|
56
|
+
tags = '{'; link = pagy_link_proc(pagy, 'class="page-link"'.freeze); responsive = pagy.responsive
|
57
|
+
|
58
|
+
tags << (pagy.prev ? %('prev':'<li class="page-item prev">#{link.call pagy.prev, pagy_t('pagy.nav.prev'.freeze), 'aria-label="previous"'.freeze}</li>',)
|
59
|
+
: %('prev':'<li class="page-item prev disabled"><a href="#" class="page-link">#{pagy_t('pagy.nav.prev'.freeze)}</a></li>',))
|
60
|
+
responsive[:items].each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
|
61
|
+
tags << if item.is_a?(Integer); %('#{item}':'<li class="page-item">#{link.call item}</li>',) # page link
|
62
|
+
elsif item.is_a?(String) ; %('#{item}':'<li class="page-item active">#{link.call item}</li>',) # active page
|
63
|
+
elsif item == :gap ; %('#{item}':'<li class="page-item gap disabled"><a href="#" class="page-link">#{pagy_t('pagy.nav.gap'.freeze)}</a></li>',) # page gap
|
64
|
+
end
|
65
|
+
end
|
66
|
+
tags << (pagy.next ? %('next':'<li class="page-item next">#{link.call pagy.next, pagy_t('pagy.nav.next'.freeze), 'aria-label="next"'.freeze}</li>'})
|
67
|
+
: %('next':'<li class="page-item next disabled"><a href="#" class="page-link">#{pagy_t('pagy.nav.next'.freeze)}</a></li>'}))
|
68
|
+
script = %(<script>PagyResponsive('#{id}', #{tags}, #{responsive[:widths].to_json}, #{responsive[:series].to_json});</script>)
|
69
|
+
%(<nav id="pagy-nav-#{id}" class="pagy-nav-bootstrap-responsive pagination" role="navigation" aria-label="pager"><ul class="pagination"></ul></nav>#{script})
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<%#
|
2
|
+
This template is i18n-ready: if you don't use i18n, then you can replace the pagy_t
|
3
|
+
calls with the actual strings ("‹ Prev", "Next ›", "…").
|
4
|
+
|
5
|
+
The link variable is set to a proc that returns the link tag.
|
6
|
+
Usage: link.call( page_number [, text [, extra_attributes_string ]])
|
7
|
+
-%>
|
8
|
+
<% link = pagy_link_proc(pagy, 'class="page-link"') -%>
|
9
|
+
<%# -%><nav aria-label="pager" class="pagy-nav-bootstrap pagination" role="navigation">
|
10
|
+
<%# -%> <ul class="pagination">
|
11
|
+
<% if pagy.prev -%> <li class="page-item prev"><%== link.call(pagy.prev, pagy_t('pagy.nav.prev'), 'aria-label="previous"') %></li>
|
12
|
+
<% else -%> <li class="page-item prev disabled"><a href="#" class="page-link"><%== pagy_t('pagy.nav.prev') %></a></li>
|
13
|
+
<% end -%>
|
14
|
+
<% pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36] -%>
|
15
|
+
<% if item.is_a?(Integer) -%> <li class="page-item"><%== link.call(item) %></li>
|
16
|
+
<% elsif item.is_a?(String) -%> <li class="page-item active"><%== link.call(item) %></li>
|
17
|
+
<% elsif item == :gap -%> <li class="page-item disabled gap"><a href="#" class="page-link"><%== pagy_t('pagy.nav.gap') %></a></li>
|
18
|
+
<% end -%>
|
19
|
+
<% end -%>
|
20
|
+
<% if pagy.next -%> <li class="page-item next"><%== link.call(pagy.next, pagy_t('pagy.nav.next'), 'aria-label="next"') %></li>
|
21
|
+
<% else -%> <li class="page-item next disabled"><a href="#" class="page-link"><%== pagy_t('pagy.nav.next') %></a></li>
|
22
|
+
<% end -%>
|
23
|
+
<%# -%> </ul>
|
24
|
+
<%# -%></nav>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
-# This template is i18n-ready: if you don't use i18n, then you can replace the pagy_t
|
2
|
+
-# calls with the actual strings ("‹ Prev", "Next ›", "…").
|
3
|
+
|
4
|
+
-# The link variable is set to a proc that returns the link tag.
|
5
|
+
-# Usage: link.call( page_number [, text [, extra_attributes_string ]])
|
6
|
+
|
7
|
+
- link = pagy_link_proc(pagy, 'class="page-link"')
|
8
|
+
|
9
|
+
%nav.pagy-nav-bootstrap.pagination{"aria-label" => "pager", :role => "navigation"}
|
10
|
+
|
11
|
+
%ul.pagination
|
12
|
+
|
13
|
+
- if pagy.prev
|
14
|
+
%li.page-item.prev!= link.call(pagy.prev, pagy_t('pagy.nav.prev'), 'aria-label="previous"')
|
15
|
+
- else
|
16
|
+
%li.page-item.prev.disabled
|
17
|
+
%a.page-link{:href => '#'}!= pagy_t('pagy.nav.prev')
|
18
|
+
|
19
|
+
- pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
|
20
|
+
- if item.is_a?(Integer) # page link
|
21
|
+
%li.page-item!= link.call(item)
|
22
|
+
|
23
|
+
- elsif item.is_a?(String) # current page
|
24
|
+
%li.page-item.active!= link.call(item)
|
25
|
+
|
26
|
+
- elsif item == :gap # page gap
|
27
|
+
%li.page-item.disabled.gap
|
28
|
+
%a.page-link{:href => "#"}!= pagy_t('pagy.nav.gap')
|
29
|
+
|
30
|
+
- if pagy.next
|
31
|
+
%li.page-item.next!= link.call(pagy.next, pagy_t('pagy.nav.next'), 'aria-label="next"')
|
32
|
+
- else
|
33
|
+
%li.page-item.next.disabled
|
34
|
+
%a.page-link{:href => '#'}!= pagy_t('pagy.nav.next')
|
@@ -0,0 +1,34 @@
|
|
1
|
+
/ This template is i18n-ready: if you don't use i18n, then you can replace the pagy_t
|
2
|
+
/ calls with the actual strings ("‹ Prev", "Next ›", "…").
|
3
|
+
|
4
|
+
/ The link variable is set to a proc that returns the link tag.
|
5
|
+
/ Usage: link.call( page_number [, text [, extra_attributes_string ]])
|
6
|
+
|
7
|
+
- link = pagy_link_proc(pagy, 'class="page-link"')
|
8
|
+
|
9
|
+
nav.pagy-nav-bootstrap.pagination role="navigation" aria-label="pager"
|
10
|
+
|
11
|
+
ul.pagination
|
12
|
+
|
13
|
+
- if pagy.prev
|
14
|
+
li.page-item.prev == link.call(pagy.prev, pagy_t('pagy.nav.prev'), 'aria-label="previous"')
|
15
|
+
- else
|
16
|
+
li.page-item.prev.disabled
|
17
|
+
a.page-link href="#" == pagy_t('pagy.nav.prev')
|
18
|
+
|
19
|
+
- pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
|
20
|
+
- if item.is_a?(Integer) # page link
|
21
|
+
li.page-item == link.call(item)
|
22
|
+
|
23
|
+
- elsif item.is_a?(String) # current page
|
24
|
+
li.page-item.active == link.call(item)
|
25
|
+
|
26
|
+
- elsif item == :gap # page gap
|
27
|
+
li.page-item.disabled.gap
|
28
|
+
a.page-link href="#" == pagy_t('pagy.nav.gap')
|
29
|
+
|
30
|
+
- if pagy.next
|
31
|
+
li.page-item.next == link.call(pagy.next, pagy_t('pagy.nav.next'), 'aria-label="next"')
|
32
|
+
- else
|
33
|
+
li.page-item.next.disabled
|
34
|
+
a.page-link href="#" == pagy_t('pagy.nav.next')
|
data/lib/pagy/frontend.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# See Pagy::Frontend API documentation: https://ddnexus.github.io/pagy/api/frontend
|
2
2
|
|
3
|
+
require 'yaml'
|
4
|
+
|
3
5
|
class Pagy
|
4
6
|
|
5
7
|
# All the code here has been optimized for performance: it may not look very pretty
|
@@ -33,14 +35,14 @@ class Pagy
|
|
33
35
|
|
34
36
|
|
35
37
|
# this works with all Rack-based frameworks (Sinatra, Padrino, Rails, ...)
|
36
|
-
def pagy_url_for(
|
37
|
-
params = request.GET.merge(
|
38
|
+
def pagy_url_for(page, page_param)
|
39
|
+
params = request.GET.merge(page_param => page)
|
38
40
|
"#{request.path}?#{Rack::Utils.build_nested_query(pagy_get_params(params))}"
|
39
41
|
end
|
40
42
|
|
41
43
|
|
42
44
|
# sub-method called only by #pagy_url_for: here for easy customization of params by overriding
|
43
|
-
def pagy_get_params(
|
45
|
+
def pagy_get_params(params) params end
|
44
46
|
|
45
47
|
|
46
48
|
MARKER = "-pagy-#{'pagy'.hash}-".freeze
|
@@ -48,34 +50,28 @@ class Pagy
|
|
48
50
|
# returns a specialized proc to generate the HTML links
|
49
51
|
def pagy_link_proc(pagy, lx=''.freeze) # "lx" means "link extra"
|
50
52
|
p_prev, p_next, p_lx = pagy.prev, pagy.next, pagy.vars[:link_extra]
|
51
|
-
a, b = %(<a href="#{pagy_url_for(MARKER)}"#{p_lx ? %( #{p_lx}) : ''.freeze}#{lx.empty? ? lx : %( #{lx})}).split(MARKER)
|
53
|
+
a, b = %(<a href="#{pagy_url_for(MARKER, pagy.vars[:page_param])}"#{p_lx ? %( #{p_lx}) : ''.freeze}#{lx.empty? ? lx : %( #{lx})}).split(MARKER)
|
52
54
|
-> (n, text=n, x=''.freeze) { "#{a}#{n}#{b}#{ if n == p_prev ; ' rel="prev"'.freeze
|
53
55
|
elsif n == p_next ; ' rel="next"'.freeze
|
54
56
|
else ''.freeze end }#{x.empty? ? x : %( #{x})}>#{text}</a>" }
|
55
57
|
end
|
56
58
|
|
57
59
|
|
58
|
-
#
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
value =
|
71
|
-
if value.is_a?(Hash)
|
72
|
-
vars.key?(:count) or return value
|
73
|
-
plural = I18N[:plurals].call(vars[:count])
|
74
|
-
value.key?(plural) or return %(invalid pluralization data: "#{path}" cannot be used with count: #{vars[:count]}; key "#{plural}" is missing.)
|
75
|
-
value = value[plural] or return %(translation missing: "#{path}")
|
76
|
-
end
|
77
|
-
sprintf value, Hash.new{|h,k| "%{#{k}}"}.merge!(vars) # interpolation
|
60
|
+
# load data from the first locale in the file
|
61
|
+
I18N_DATA = YAML.load_file(I18N[:file]).first[1].freeze
|
62
|
+
|
63
|
+
# Similar to I18n.t for interpolation and pluralization but without translation
|
64
|
+
# Use only for single-language apps: it is specialized for pagy and 5x faster than I18n.t
|
65
|
+
# See also https://ddnexus.github.io/pagy/extras/i18n to use the standard I18n gem instead
|
66
|
+
def pagy_t(path, vars={})
|
67
|
+
value = I18N_DATA.dig(*path.to_s.split('.'.freeze)) or return %(translation missing: "#{path}")
|
68
|
+
if value.is_a?(Hash)
|
69
|
+
vars.key?(:count) or return value
|
70
|
+
plural = I18N[:plurals].call(vars[:count])
|
71
|
+
value.key?(plural) or return %(invalid pluralization data: "#{path}" cannot be used with count: #{vars[:count]}; key "#{plural}" is missing.)
|
72
|
+
value = value[plural] or return %(translation missing: "#{path}")
|
78
73
|
end
|
74
|
+
sprintf value, Hash.new{|_,k| "%{#{k}}"}.merge!(vars) # interpolation
|
79
75
|
end
|
80
76
|
|
81
77
|
end
|
data/pagy.gemspec
CHANGED
@@ -29,5 +29,13 @@ Gem::Specification.new do |s|
|
|
29
29
|
s.add_development_dependency 'benchmark-ips'
|
30
30
|
s.add_development_dependency 'kalibera'
|
31
31
|
s.add_development_dependency 'memory_profiler'
|
32
|
+
s.add_development_dependency 'rubocop', '~> 0.55.0' # needs to be fixed since it constantly adds new cops
|
33
|
+
|
34
|
+
|
35
|
+
s.post_install_message = <<EOM
|
36
|
+
******************************************************************************
|
37
|
+
Pagy CHANGELOG: https://github.com/ddnexus/pagy/blob/master/CHANGELOG.md
|
38
|
+
******************************************************************************
|
39
|
+
EOM
|
32
40
|
|
33
41
|
end
|
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: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Domizio Demichelis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-05-
|
11
|
+
date: 2018-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -136,6 +136,20 @@ dependencies:
|
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rubocop
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 0.55.0
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: 0.55.0
|
139
153
|
description: 'Agnostic pagination in plain ruby: it works with any framework, ORM
|
140
154
|
and DB type, with all kinds of collections, even pre-paginated, scopes, Arrays,
|
141
155
|
JSON data... and just whatever you can count. Easy to use and customize, very fast
|
@@ -150,16 +164,30 @@ files:
|
|
150
164
|
- lib/locales/pagy.yml
|
151
165
|
- lib/pagy.rb
|
152
166
|
- lib/pagy/backend.rb
|
167
|
+
- lib/pagy/extras/array.rb
|
168
|
+
- lib/pagy/extras/bootstrap.rb
|
169
|
+
- lib/pagy/extras/compact.rb
|
170
|
+
- lib/pagy/extras/i18n.rb
|
171
|
+
- lib/pagy/extras/initializer_example.rb
|
172
|
+
- lib/pagy/extras/javascripts/pagy-compact.js
|
173
|
+
- lib/pagy/extras/javascripts/pagy-responsive.js
|
174
|
+
- lib/pagy/extras/responsive.rb
|
175
|
+
- lib/pagy/extras/templates/nav.html.erb
|
176
|
+
- lib/pagy/extras/templates/nav.html.haml
|
177
|
+
- lib/pagy/extras/templates/nav.html.slim
|
178
|
+
- lib/pagy/extras/templates/nav_bootstrap.html.erb
|
179
|
+
- lib/pagy/extras/templates/nav_bootstrap.html.haml
|
180
|
+
- lib/pagy/extras/templates/nav_bootstrap.html.slim
|
153
181
|
- lib/pagy/frontend.rb
|
154
|
-
- lib/templates/nav.html.erb
|
155
|
-
- lib/templates/nav.html.haml
|
156
|
-
- lib/templates/nav.html.slim
|
157
182
|
- pagy.gemspec
|
158
183
|
homepage: https://github.com/ddnexus/pagy
|
159
184
|
licenses:
|
160
185
|
- MIT
|
161
186
|
metadata: {}
|
162
|
-
post_install_message:
|
187
|
+
post_install_message: |
|
188
|
+
******************************************************************************
|
189
|
+
Pagy CHANGELOG: https://github.com/ddnexus/pagy/blob/master/CHANGELOG.md
|
190
|
+
******************************************************************************
|
163
191
|
rdoc_options: []
|
164
192
|
require_paths:
|
165
193
|
- lib
|