pagy 0.7.2 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|