kaminari-core 1.2.1 → 1.3.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/app/views/kaminari/_first_page.html.erb +2 -1
- data/app/views/kaminari/_first_page.html.haml +2 -1
- data/app/views/kaminari/_first_page.html.slim +2 -1
- data/app/views/kaminari/_last_page.html.erb +2 -1
- data/app/views/kaminari/_last_page.html.haml +2 -1
- data/app/views/kaminari/_last_page.html.slim +2 -1
- data/app/views/kaminari/_next_page.html.erb +2 -1
- data/app/views/kaminari/_next_page.html.haml +2 -1
- data/app/views/kaminari/_next_page.html.slim +2 -1
- data/app/views/kaminari/_page.html.erb +2 -1
- data/app/views/kaminari/_page.html.haml +2 -1
- data/app/views/kaminari/_page.html.slim +2 -1
- data/app/views/kaminari/_paginator.html.erb +1 -0
- data/app/views/kaminari/_paginator.html.haml +5 -3
- data/app/views/kaminari/_paginator.html.slim +5 -3
- data/app/views/kaminari/_prev_page.html.erb +2 -1
- data/app/views/kaminari/_prev_page.html.haml +2 -1
- data/app/views/kaminari/_prev_page.html.slim +2 -1
- data/config/locales/kaminari.yml +1 -1
- data/kaminari-core.gemspec +7 -0
- data/lib/generators/kaminari/views_generator.rb +39 -19
- data/lib/kaminari/core/version.rb +1 -1
- data/lib/kaminari/core.rb +4 -0
- data/lib/kaminari/engine.rb +3 -0
- data/lib/kaminari/helpers/helper_methods.rb +34 -14
- data/lib/kaminari/helpers/paginator.rb +27 -17
- data/lib/kaminari/helpers/tags.rb +104 -35
- data/lib/kaminari/models/array_extension.rb +18 -2
- data/lib/kaminari/models/configuration_methods.rb +1 -1
- data/lib/kaminari/models/page_scope_methods.rb +28 -15
- metadata +94 -89
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d08a6963a92273028b03d21b148a1a7d4fb8f7033b315e1af492b54eaf9ba790
|
|
4
|
+
data.tar.gz: 6aa9625e5db4476c1e76deaa7e548e9821dc19411ff09c753cbb9a16c146e81e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 497e6516b7f39d799c9c69a772c3985d1da0f4714e42f1d011686b273d178c534513b074de56d5c888e98ec4f70ca78718c211b918a2d584b5b0ef040b8f697d
|
|
7
|
+
data.tar.gz: 32cce623d1212f46a77c41974ef225c93b152fcb7ed41de7f03e21c825c8b42b2e75ec1777afd0e0719ea9aa27c77238195a1ce2b16f8ee433fcc04b0cbc212c
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
total_pages: total number of pages
|
|
6
6
|
per_page: number of items to fetch per page
|
|
7
7
|
remote: data-remote
|
|
8
|
+
data: data-* attributes
|
|
8
9
|
-%>
|
|
9
10
|
<span class="first">
|
|
10
|
-
<%= link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, remote: remote %>
|
|
11
|
+
<%= link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, remote: remote, data: data %>
|
|
11
12
|
</span>
|
|
@@ -5,5 +5,6 @@
|
|
|
5
5
|
-# total_pages: total number of pages
|
|
6
6
|
-# per_page: number of items to fetch per page
|
|
7
7
|
-# remote: data-remote
|
|
8
|
+
-# data: data-* attributes
|
|
8
9
|
%span.first
|
|
9
|
-
= link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, remote: remote
|
|
10
|
+
= link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, remote: remote, data: data
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
total_pages : total number of pages
|
|
6
6
|
per_page : number of items to fetch per page
|
|
7
7
|
remote : data-remote
|
|
8
|
+
data : data-* attributes
|
|
8
9
|
span.first
|
|
9
|
-
== link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, remote: remote
|
|
10
|
+
== link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, remote: remote, data: data
|
|
10
11
|
'
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
total_pages: total number of pages
|
|
6
6
|
per_page: number of items to fetch per page
|
|
7
7
|
remote: data-remote
|
|
8
|
+
data: data-* attributes
|
|
8
9
|
-%>
|
|
9
10
|
<span class="last">
|
|
10
|
-
<%= link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, remote: remote %>
|
|
11
|
+
<%= link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, remote: remote, data: data %>
|
|
11
12
|
</span>
|
|
@@ -5,5 +5,6 @@
|
|
|
5
5
|
-# total_pages: total number of pages
|
|
6
6
|
-# per_page: number of items to fetch per page
|
|
7
7
|
-# remote: data-remote
|
|
8
|
+
-# data: data-* attributes
|
|
8
9
|
%span.last
|
|
9
|
-
= link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, remote: remote
|
|
10
|
+
= link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, remote: remote, data: data
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
total_pages : total number of pages
|
|
6
6
|
per_page : number of items to fetch per page
|
|
7
7
|
remote : data-remote
|
|
8
|
+
data : data-* attributes
|
|
8
9
|
span.last
|
|
9
|
-
== link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, remote: remote
|
|
10
|
+
== link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, remote: remote, data: data
|
|
10
11
|
'
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
total_pages: total number of pages
|
|
6
6
|
per_page: number of items to fetch per page
|
|
7
7
|
remote: data-remote
|
|
8
|
+
data: data-* attributes
|
|
8
9
|
-%>
|
|
9
10
|
<span class="next">
|
|
10
|
-
<%= link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, rel: 'next', remote: remote %>
|
|
11
|
+
<%= link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, rel: 'next', remote: remote, data: data %>
|
|
11
12
|
</span>
|
|
@@ -5,5 +5,6 @@
|
|
|
5
5
|
-# total_pages: total number of pages
|
|
6
6
|
-# per_page: number of items to fetch per page
|
|
7
7
|
-# remote: data-remote
|
|
8
|
+
-# data: data-* attributes
|
|
8
9
|
%span.next
|
|
9
|
-
= link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, rel: 'next', remote: remote
|
|
10
|
+
= link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, rel: 'next', remote: remote, data: data
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
total_pages : total number of pages
|
|
6
6
|
per_page : number of items to fetch per page
|
|
7
7
|
remote : data-remote
|
|
8
|
+
data : data-* attributes
|
|
8
9
|
span.next
|
|
9
|
-
== link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, rel: 'next', remote: remote
|
|
10
|
+
== link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, rel: 'next', remote: remote, data: data
|
|
10
11
|
'
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
total_pages: total number of pages
|
|
7
7
|
per_page: number of items to fetch per page
|
|
8
8
|
remote: data-remote
|
|
9
|
+
data: data-* attributes
|
|
9
10
|
-%>
|
|
10
11
|
<span class="page<%= ' current' if page.current? %>">
|
|
11
|
-
<%= link_to_unless page.current?, page, url, {remote: remote, rel: page.rel} %>
|
|
12
|
+
<%= link_to_unless page.current?, page, url, {remote: remote, data: data, rel: page.rel} %>
|
|
12
13
|
</span>
|
|
@@ -6,5 +6,6 @@
|
|
|
6
6
|
-# total_pages: total number of pages
|
|
7
7
|
-# per_page: number of items to fetch per page
|
|
8
8
|
-# remote: data-remote
|
|
9
|
+
-# data: data-* attributes
|
|
9
10
|
%span{class: "page#{' current' if page.current?}"}
|
|
10
|
-
= link_to_unless page.current?, page, url, {remote: remote, rel: page.rel}
|
|
11
|
+
= link_to_unless page.current?, page, url, {remote: remote, data: data, rel: page.rel}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
total_pages : total number of pages
|
|
7
7
|
per_page : number of items to fetch per page
|
|
8
8
|
remote : data-remote
|
|
9
|
+
data : data-* attributes
|
|
9
10
|
span class="page#{' current' if page.current?}"
|
|
10
|
-
== link_to_unless page.current?, page, url, {remote: remote, rel: page.rel}
|
|
11
|
+
== link_to_unless page.current?, page, url, {remote: remote, data: data, rel: page.rel}
|
|
11
12
|
'
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
-# total_pages: total number of pages
|
|
5
5
|
-# per_page: number of items to fetch per page
|
|
6
6
|
-# remote: data-remote
|
|
7
|
+
-# data: data-* attributes
|
|
7
8
|
-# paginator: the paginator that renders the pagination tags inside
|
|
8
9
|
= paginator.render do
|
|
9
|
-
%nav.pagination
|
|
10
|
+
%nav.pagination{role: "navigation", "aria-label" => "pager"}
|
|
10
11
|
= first_page_tag unless current_page.first?
|
|
11
12
|
= prev_page_tag unless current_page.first?
|
|
12
13
|
- each_page do |page|
|
|
@@ -14,5 +15,6 @@
|
|
|
14
15
|
= page_tag page
|
|
15
16
|
- elsif !page.was_truncated?
|
|
16
17
|
= gap_tag
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
- unless current_page.out_of_range?
|
|
19
|
+
= next_page_tag unless current_page.last?
|
|
20
|
+
= last_page_tag unless current_page.last?
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
total_pages : total number of pages
|
|
5
5
|
per_page : number of items to fetch per page
|
|
6
6
|
remote : data-remote
|
|
7
|
+
data : data-* attributes
|
|
7
8
|
paginator : the paginator that renders the pagination tags inside
|
|
8
9
|
|
|
9
10
|
== paginator.render do
|
|
10
|
-
nav.pagination
|
|
11
|
+
nav.pagination role="navigation" aria-label="pager"
|
|
11
12
|
== first_page_tag unless current_page.first?
|
|
12
13
|
== prev_page_tag unless current_page.first?
|
|
13
14
|
- each_page do |page|
|
|
@@ -15,5 +16,6 @@
|
|
|
15
16
|
== page_tag page
|
|
16
17
|
- elsif !page.was_truncated?
|
|
17
18
|
== gap_tag
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
- unless current_page.out_of_range?
|
|
20
|
+
== next_page_tag unless current_page.last?
|
|
21
|
+
== last_page_tag unless current_page.last?
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
total_pages: total number of pages
|
|
6
6
|
per_page: number of items to fetch per page
|
|
7
7
|
remote: data-remote
|
|
8
|
+
data: data-* attributes
|
|
8
9
|
-%>
|
|
9
10
|
<span class="prev">
|
|
10
|
-
<%= link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, rel: 'prev', remote: remote %>
|
|
11
|
+
<%= link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, rel: 'prev', remote: remote, data: data %>
|
|
11
12
|
</span>
|
|
@@ -5,5 +5,6 @@
|
|
|
5
5
|
-# total_pages: total number of pages
|
|
6
6
|
-# per_page: number of items to fetch per page
|
|
7
7
|
-# remote: data-remote
|
|
8
|
+
-# data: data-* attributes
|
|
8
9
|
%span.prev
|
|
9
|
-
= link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, rel: 'prev', remote: remote
|
|
10
|
+
= link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, rel: 'prev', remote: remote, data: data
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
total_pages : total number of pages
|
|
6
6
|
per_page : number of items to fetch per page
|
|
7
7
|
remote : data-remote
|
|
8
|
+
data : data-* attributes
|
|
8
9
|
span.prev
|
|
9
|
-
== link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, rel: 'prev', remote: remote
|
|
10
|
+
== link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, rel: 'prev', remote: remote, data: data
|
|
10
11
|
'
|
data/config/locales/kaminari.yml
CHANGED
|
@@ -20,4 +20,4 @@ en:
|
|
|
20
20
|
one: "Displaying <b>1</b> %{entry_name}"
|
|
21
21
|
other: "Displaying <b>all %{count}</b> %{entry_name}"
|
|
22
22
|
more_pages:
|
|
23
|
-
display_entries: "Displaying %{entry_name} <b>%{first}
|
|
23
|
+
display_entries: "Displaying %{entry_name} <b>%{first}–%{last}</b> of <b>%{total}</b> in total"
|
data/kaminari-core.gemspec
CHANGED
|
@@ -14,6 +14,13 @@ Gem::Specification.new do |spec|
|
|
|
14
14
|
spec.description = 'kaminari-core includes pagination logic independent from ORMs and view libraries'
|
|
15
15
|
spec.homepage = 'https://github.com/kaminari/kaminari'
|
|
16
16
|
spec.license = "MIT"
|
|
17
|
+
|
|
18
|
+
spec.metadata = {
|
|
19
|
+
'changelog_uri' => 'https://github.com/kaminari/kaminari/blob/master/CHANGELOG.md',
|
|
20
|
+
'source_code_uri' => 'https://github.com/kaminari/kaminari/tree/master/kaminari-core',
|
|
21
|
+
'rubygems_mfa_required' => 'true'
|
|
22
|
+
}
|
|
23
|
+
|
|
17
24
|
spec.required_ruby_version = '>= 2.0.0'
|
|
18
25
|
|
|
19
26
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
@@ -9,8 +9,9 @@ module Kaminari
|
|
|
9
9
|
class_option :template_engine, type: :string, aliases: '-e', desc: 'Template engine for the views. Available options are "erb", "haml", and "slim".'
|
|
10
10
|
class_option :views_prefix, type: :string, desc: 'Prefix for path to put views in.'
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
class << self
|
|
13
|
+
def banner #:nodoc:
|
|
14
|
+
<<-BANNER.chomp
|
|
14
15
|
rails g kaminari:views THEME [options]
|
|
15
16
|
|
|
16
17
|
Copies all paginator partial templates to your application.
|
|
@@ -21,29 +22,35 @@ rails g kaminari:views THEME [options]
|
|
|
21
22
|
This one is used internally while you don't override the partials.
|
|
22
23
|
#{themes.map {|t| " - #{t.name}\n#{t.description}"}.join("\n")}
|
|
23
24
|
BANNER
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def themes
|
|
28
|
+
@themes ||= GitHubApiHelper.get_files_in_master.group_by {|fn, _| fn[0...(fn.index('/') || 0)]}.delete_if {|fn, _| fn.blank?}.map do |name, files|
|
|
29
|
+
Theme.new name, files
|
|
30
|
+
end
|
|
31
|
+
rescue *GitHubApiHelper::NETWORK_ERRORS
|
|
32
|
+
[]
|
|
33
|
+
end
|
|
24
34
|
end
|
|
25
35
|
|
|
26
36
|
desc ''
|
|
27
37
|
def copy_or_fetch #:nodoc:
|
|
28
38
|
return copy_default_views if file_name == 'default'
|
|
29
39
|
|
|
30
|
-
if
|
|
40
|
+
if self.class.themes.empty?
|
|
41
|
+
say "could not fetch the themes from GitHub. Please try again later."
|
|
42
|
+
elsif (theme = self.class.themes.detect {|t| t.name == file_name})
|
|
31
43
|
if download_templates(theme).empty?
|
|
32
44
|
say "template_engine: #{template_engine} is not available for theme: #{file_name}"
|
|
33
45
|
end
|
|
34
46
|
else
|
|
35
47
|
say "no such theme: #{file_name}\n available themes: #{self.class.themes.map(&:name).join ', '}"
|
|
36
48
|
end
|
|
49
|
+
rescue *GitHubApiHelper::NETWORK_ERRORS => e
|
|
50
|
+
say "could not download the templates from GitHub (#{e.message}). Please try again later."
|
|
37
51
|
end
|
|
38
52
|
|
|
39
53
|
private
|
|
40
|
-
def self.themes
|
|
41
|
-
@themes ||= GitHubApiHelper.get_files_in_master.group_by {|fn, _| fn[0...(fn.index('/') || 0)]}.delete_if {|fn, _| fn.blank?}.map do |name, files|
|
|
42
|
-
Theme.new name, files
|
|
43
|
-
end
|
|
44
|
-
rescue SocketError
|
|
45
|
-
[]
|
|
46
|
-
end
|
|
47
54
|
|
|
48
55
|
def download_templates(theme)
|
|
49
56
|
theme.templates_for(template_engine).each do |template|
|
|
@@ -68,14 +75,21 @@ BANNER
|
|
|
68
75
|
end
|
|
69
76
|
|
|
70
77
|
def template_engine
|
|
71
|
-
|
|
78
|
+
@template_engine ||= begin
|
|
79
|
+
engine = options[:template_engine].try(:to_s).try(:downcase).presence || 'erb'
|
|
72
80
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
if engine == 'haml' || engine == 'slim'
|
|
82
|
+
Kaminari.deprecator.warn 'The -e option is deprecated and will be removed in the near future. Please use the html2slim gem or the html2haml gem ' \
|
|
83
|
+
'to convert erb templates manually.'
|
|
84
|
+
end
|
|
77
85
|
|
|
78
|
-
|
|
86
|
+
if %w[erb haml slim].include?(engine)
|
|
87
|
+
engine
|
|
88
|
+
else
|
|
89
|
+
say "template_engine: #{engine} is not supported. Falling back to erb."
|
|
90
|
+
'erb'
|
|
91
|
+
end
|
|
92
|
+
end
|
|
79
93
|
end
|
|
80
94
|
end
|
|
81
95
|
|
|
@@ -103,6 +117,8 @@ BANNER
|
|
|
103
117
|
file = @templates.detect(&:description?)
|
|
104
118
|
return "#{' ' * 12}#{name}" unless file
|
|
105
119
|
GitHubApiHelper.get_content_for("#{@name}/#{file.name}").chomp.gsub(/^/, ' ' * 12)
|
|
120
|
+
rescue *GitHubApiHelper::NETWORK_ERRORS
|
|
121
|
+
"#{' ' * 12}#{name}"
|
|
106
122
|
end
|
|
107
123
|
|
|
108
124
|
def templates_for(template_engine) #:nodoc:
|
|
@@ -112,12 +128,16 @@ BANNER
|
|
|
112
128
|
|
|
113
129
|
module GitHubApiHelper
|
|
114
130
|
require 'open-uri'
|
|
131
|
+
require 'net/http'
|
|
132
|
+
|
|
133
|
+
# e.g. offline, timed out, or exceeded the API rate limit
|
|
134
|
+
NETWORK_ERRORS = [SocketError, SystemCallError, Timeout::Error, OpenSSL::SSL::SSLError, OpenURI::HTTPError].freeze
|
|
115
135
|
|
|
116
136
|
def get_files_in_master
|
|
117
|
-
master_tree_sha = open('https://api.github.com/repos/amatsuda/kaminari_themes/git/refs/heads/master') do |json|
|
|
137
|
+
master_tree_sha = URI.open('https://api.github.com/repos/amatsuda/kaminari_themes/git/refs/heads/master') do |json|
|
|
118
138
|
ActiveSupport::JSON.decode(json.read)['object']['sha']
|
|
119
139
|
end
|
|
120
|
-
|
|
140
|
+
URI.parse("https://api.github.com/repos/amatsuda/kaminari_themes/git/trees/#{master_tree_sha}?recursive=1").open do |json|
|
|
121
141
|
blobs = ActiveSupport::JSON.decode(json.read)['tree'].find_all {|i| i['type'] == 'blob' }
|
|
122
142
|
blobs.map do |blob|
|
|
123
143
|
[blob['path'], blob['sha']]
|
|
@@ -127,7 +147,7 @@ BANNER
|
|
|
127
147
|
module_function :get_files_in_master
|
|
128
148
|
|
|
129
149
|
def get_content_for(path)
|
|
130
|
-
|
|
150
|
+
URI.parse("https://api.github.com/repos/amatsuda/kaminari_themes/contents/#{path}").open do |json|
|
|
131
151
|
Base64.decode64(ActiveSupport::JSON.decode(json.read)['content'])
|
|
132
152
|
end
|
|
133
153
|
end
|
data/lib/kaminari/core.rb
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Kaminari
|
|
4
|
+
def self.deprecator
|
|
5
|
+
@deprecator ||= ActiveSupport::Deprecation.new("2.0", "kaminari-core")
|
|
6
|
+
end
|
|
4
7
|
end
|
|
5
8
|
|
|
6
9
|
# load Rails/Railtie
|
|
@@ -14,6 +17,7 @@ end
|
|
|
14
17
|
require 'kaminari/config'
|
|
15
18
|
require 'kaminari/exceptions'
|
|
16
19
|
require 'kaminari/helpers/paginator'
|
|
20
|
+
require 'kaminari/helpers/helper_methods'
|
|
17
21
|
require 'kaminari/models/page_scope_methods'
|
|
18
22
|
require 'kaminari/models/configuration_methods'
|
|
19
23
|
require 'kaminari/models/array_extension'
|
data/lib/kaminari/engine.rb
CHANGED
|
@@ -4,14 +4,14 @@ module Kaminari
|
|
|
4
4
|
module Helpers
|
|
5
5
|
|
|
6
6
|
# The Kaminari::Helpers::UrlHelper module provides useful methods for
|
|
7
|
-
# generating a path or url to a
|
|
7
|
+
# generating a path or url to a particular page. A class must implement the
|
|
8
8
|
# following methods:
|
|
9
9
|
#
|
|
10
10
|
# * <tt>url_for</tt>: A method that generates an actual path
|
|
11
11
|
# * <tt>params</tt>: A method that returns query string parameters
|
|
12
12
|
# * <tt>request</tt>: A method that returns a Rack::Request object
|
|
13
13
|
#
|
|
14
|
-
# A normal Rails controller implements all the methods, which
|
|
14
|
+
# A normal Rails controller implements all the methods, which make it
|
|
15
15
|
# trivial to use this module:
|
|
16
16
|
#
|
|
17
17
|
# ==== Examples
|
|
@@ -20,10 +20,10 @@ module Kaminari
|
|
|
20
20
|
# include Kaminari::Helpers::UrlHelper
|
|
21
21
|
#
|
|
22
22
|
# def index
|
|
23
|
-
#
|
|
23
|
+
# @users = User.page(1)
|
|
24
24
|
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
25
|
+
# path_to_next_page(@items)
|
|
26
|
+
# # => /items?page=2
|
|
27
27
|
# end
|
|
28
28
|
# end
|
|
29
29
|
#
|
|
@@ -41,7 +41,12 @@ module Kaminari
|
|
|
41
41
|
def next_page_url(scope, options = {})
|
|
42
42
|
"#{request.base_url}#{next_page_path(scope, options)}" if scope.next_page
|
|
43
43
|
end
|
|
44
|
-
alias
|
|
44
|
+
alias url_to_next_page next_page_url
|
|
45
|
+
|
|
46
|
+
def path_to_next_url(scope, options = {})
|
|
47
|
+
Kaminari.deprecator.warn 'path_to_next_url is deprecated. Use next_page_url or url_to_next_page instead.'
|
|
48
|
+
next_page_url(scope, options)
|
|
49
|
+
end
|
|
45
50
|
|
|
46
51
|
# A helper that calculates the url to the previous page.
|
|
47
52
|
#
|
|
@@ -105,10 +110,12 @@ module Kaminari
|
|
|
105
110
|
# * <tt>:params</tt> - url_for parameters for the links (:controller, :action, etc.)
|
|
106
111
|
# * <tt>:param_name</tt> - parameter name for page number in the links (:page by default)
|
|
107
112
|
# * <tt>:remote</tt> - Ajax? (false by default)
|
|
113
|
+
# * <tt>:data</tt> - data-* attributes for the links (e.g. <tt>{turbo_frame: 'users'}</tt>)
|
|
108
114
|
# * <tt>:paginator_class</tt> - Specify a custom Paginator (Kaminari::Helpers::Paginator by default)
|
|
109
115
|
# * <tt>:template</tt> - Specify a custom template renderer for rendering the Paginator (receiver by default)
|
|
110
116
|
# * <tt>:ANY_OTHER_VALUES</tt> - Any other hash key & values would be directly passed into each tag as :locals value.
|
|
111
117
|
def paginate(scope, paginator_class: Kaminari::Helpers::Paginator, template: nil, **options)
|
|
118
|
+
options[:data] ||= {}
|
|
112
119
|
options[:total_pages] ||= scope.total_pages
|
|
113
120
|
options.reverse_merge! current_page: scope.current_page, per_page: scope.limit_value, remote: false
|
|
114
121
|
|
|
@@ -188,23 +195,36 @@ module Kaminari
|
|
|
188
195
|
#
|
|
189
196
|
# By default, the message will use the humanized class name of objects
|
|
190
197
|
# in collection: for instance, "project types" for ProjectType models.
|
|
191
|
-
# The namespace will be
|
|
198
|
+
# The namespace will be cut out and only the last name will be used.
|
|
192
199
|
# Override this with the <tt>:entry_name</tt> parameter:
|
|
193
200
|
#
|
|
194
201
|
# <%= page_entries_info @posts, entry_name: 'item' %>
|
|
195
202
|
# #-> Displaying items 6 - 10 of 26 in total
|
|
196
203
|
def page_entries_info(collection, entry_name: nil)
|
|
204
|
+
records = collection.respond_to?(:records) ? collection.records : collection.to_a
|
|
205
|
+
page_size = records.size
|
|
197
206
|
entry_name = if entry_name
|
|
198
|
-
entry_name.pluralize(
|
|
207
|
+
pluralized = entry_name.pluralize(page_size, I18n.locale)
|
|
208
|
+
entry_name.html_safe? ? pluralized.html_safe : pluralized
|
|
199
209
|
else
|
|
200
|
-
collection.entry_name(count:
|
|
210
|
+
collection.entry_name(count: page_size).downcase
|
|
201
211
|
end
|
|
212
|
+
# the translated message is marked as html_safe, so the interpolated entry_name has to be escaped here
|
|
213
|
+
entry_name = ERB::Util.html_escape entry_name
|
|
202
214
|
|
|
203
|
-
if collection.
|
|
215
|
+
if collection.out_of_range?
|
|
216
|
+
# an out of range page displays no entries
|
|
217
|
+
t('helpers.page_entries_info.one_page.display_entries', entry_name: entry_name, count: 0)
|
|
218
|
+
elsif collection.total_pages < 2
|
|
204
219
|
t('helpers.page_entries_info.one_page.display_entries', entry_name: entry_name, count: collection.total_count)
|
|
205
220
|
else
|
|
206
221
|
from = collection.offset_value + 1
|
|
207
|
-
to
|
|
222
|
+
to =
|
|
223
|
+
if collection.is_a? ::Kaminari::PaginatableArray
|
|
224
|
+
[collection.offset_value + collection.limit_value, collection.total_count].min
|
|
225
|
+
else
|
|
226
|
+
collection.offset_value + page_size
|
|
227
|
+
end
|
|
208
228
|
|
|
209
229
|
t('helpers.page_entries_info.more_pages.display_entries', entry_name: entry_name, first: from, last: to, total: collection.total_count)
|
|
210
230
|
end.html_safe
|
|
@@ -226,15 +246,15 @@ module Kaminari
|
|
|
226
246
|
# <%= rel_next_prev_link_tags @items %>
|
|
227
247
|
# <% end %>
|
|
228
248
|
#
|
|
229
|
-
# #-> <link rel="next" href="/items/page/3"
|
|
249
|
+
# #-> <link rel="next" href="/items/page/3"><link rel="prev" href="/items/page/1">
|
|
230
250
|
#
|
|
231
251
|
def rel_next_prev_link_tags(scope, options = {})
|
|
232
252
|
next_page = path_to_next_page(scope, options)
|
|
233
253
|
prev_page = path_to_prev_page(scope, options)
|
|
234
254
|
|
|
235
255
|
output = String.new
|
|
236
|
-
output << %Q|<link rel="next" href="#{next_page}"
|
|
237
|
-
output << %Q|<link rel="prev" href="#{prev_page}"
|
|
256
|
+
output << %Q|<link rel="next" href="#{next_page}">| if next_page
|
|
257
|
+
output << %Q|<link rel="prev" href="#{prev_page}">| if prev_page
|
|
238
258
|
output.html_safe
|
|
239
259
|
end
|
|
240
260
|
end
|
|
@@ -8,9 +8,13 @@ module Kaminari
|
|
|
8
8
|
# The main container tag
|
|
9
9
|
class Paginator < Tag
|
|
10
10
|
def initialize(template, window: nil, outer_window: Kaminari.config.outer_window, left: Kaminari.config.left, right: Kaminari.config.right, inner_window: Kaminari.config.window, **options) #:nodoc:
|
|
11
|
+
super template, **options
|
|
12
|
+
|
|
11
13
|
@window_options = {window: window || inner_window, left: left.zero? ? outer_window : left, right: right.zero? ? outer_window : right}
|
|
12
14
|
|
|
13
|
-
@
|
|
15
|
+
@last = nil
|
|
16
|
+
# shared by all the tags in this paginator
|
|
17
|
+
@url_cache, @partial_cache = {}, {}
|
|
14
18
|
@window_options.merge! @options
|
|
15
19
|
@window_options[:current_page] = @options[:current_page] = PageProxy.new(@window_options, @options[:current_page], nil)
|
|
16
20
|
|
|
@@ -59,13 +63,13 @@ module Kaminari
|
|
|
59
63
|
private :relevant_pages
|
|
60
64
|
|
|
61
65
|
def page_tag(page)
|
|
62
|
-
@last = Page.new @template, **@options.merge(page: page)
|
|
66
|
+
@last = Page.new @template, param_name: @param_name, theme: @theme, views_prefix: @views_prefix, internal_params: @params, internal_url_cache: @url_cache, internal_partial_cache: @partial_cache, **@options.merge(page: page)
|
|
63
67
|
end
|
|
64
68
|
|
|
65
69
|
%w[first_page prev_page next_page last_page gap].each do |tag|
|
|
66
70
|
eval <<-DEF, nil, __FILE__, __LINE__ + 1
|
|
67
71
|
def #{tag}_tag
|
|
68
|
-
@last = #{tag.classify}.new @template, **@options
|
|
72
|
+
@last = #{tag.classify}.new @template, param_name: @param_name, theme: @theme, views_prefix: @views_prefix, internal_params: @params, internal_url_cache: @url_cache, internal_partial_cache: @partial_cache, **@options
|
|
69
73
|
end
|
|
70
74
|
DEF
|
|
71
75
|
end
|
|
@@ -78,8 +82,8 @@ module Kaminari
|
|
|
78
82
|
end
|
|
79
83
|
|
|
80
84
|
# delegates view helper methods to @template
|
|
81
|
-
def method_missing(name, *args, &block)
|
|
82
|
-
@template.respond_to?(name) ? @template.send(name, *args, &block) : super
|
|
85
|
+
def method_missing(name, *args, **kwargs, &block)
|
|
86
|
+
@template.respond_to?(name) ? @template.send(name, *args, **kwargs, &block) : super
|
|
83
87
|
end
|
|
84
88
|
private :method_missing
|
|
85
89
|
|
|
@@ -88,7 +92,13 @@ module Kaminari
|
|
|
88
92
|
include Comparable
|
|
89
93
|
|
|
90
94
|
def initialize(options, page, last) #:nodoc:
|
|
91
|
-
@
|
|
95
|
+
@page = page
|
|
96
|
+
@current_page = options[:current_page]
|
|
97
|
+
@total_pages = options[:total_pages]
|
|
98
|
+
@left = options[:left]
|
|
99
|
+
@right = options[:right]
|
|
100
|
+
@window = options[:window]
|
|
101
|
+
@was_truncated = last.is_a? Gap
|
|
92
102
|
end
|
|
93
103
|
|
|
94
104
|
# the page number
|
|
@@ -98,7 +108,7 @@ module Kaminari
|
|
|
98
108
|
|
|
99
109
|
# current page or not
|
|
100
110
|
def current?
|
|
101
|
-
@page == @
|
|
111
|
+
@page == @current_page
|
|
102
112
|
end
|
|
103
113
|
|
|
104
114
|
# the first page or not
|
|
@@ -108,17 +118,17 @@ module Kaminari
|
|
|
108
118
|
|
|
109
119
|
# the last page or not
|
|
110
120
|
def last?
|
|
111
|
-
@page == @
|
|
121
|
+
@page == @total_pages
|
|
112
122
|
end
|
|
113
123
|
|
|
114
124
|
# the previous page or not
|
|
115
125
|
def prev?
|
|
116
|
-
@page == @
|
|
126
|
+
@page == @current_page - 1
|
|
117
127
|
end
|
|
118
128
|
|
|
119
129
|
# the next page or not
|
|
120
130
|
def next?
|
|
121
|
-
@page == @
|
|
131
|
+
@page == @current_page + 1
|
|
122
132
|
end
|
|
123
133
|
|
|
124
134
|
# relationship with the current page
|
|
@@ -132,33 +142,33 @@ module Kaminari
|
|
|
132
142
|
|
|
133
143
|
# within the left outer window or not
|
|
134
144
|
def left_outer?
|
|
135
|
-
@page <= @
|
|
145
|
+
@page <= @left
|
|
136
146
|
end
|
|
137
147
|
|
|
138
148
|
# within the right outer window or not
|
|
139
149
|
def right_outer?
|
|
140
|
-
@
|
|
150
|
+
@total_pages - @page < @right
|
|
141
151
|
end
|
|
142
152
|
|
|
143
153
|
# inside the inner window or not
|
|
144
154
|
def inside_window?
|
|
145
|
-
(@
|
|
155
|
+
(@current_page - @page).abs <= @window
|
|
146
156
|
end
|
|
147
157
|
|
|
148
158
|
# Current page is an isolated gap or not
|
|
149
159
|
def single_gap?
|
|
150
|
-
((@page == @
|
|
151
|
-
((@page == @
|
|
160
|
+
((@page == @current_page - @window - 1) && (@page == @left + 1)) ||
|
|
161
|
+
((@page == @current_page + @window + 1) && (@page == @total_pages - @right))
|
|
152
162
|
end
|
|
153
163
|
|
|
154
164
|
# The page number exceeds the range of pages or not
|
|
155
165
|
def out_of_range?
|
|
156
|
-
@page > @
|
|
166
|
+
@page > @total_pages
|
|
157
167
|
end
|
|
158
168
|
|
|
159
169
|
# The last rendered tag was "truncated" or not
|
|
160
170
|
def was_truncated?
|
|
161
|
-
@
|
|
171
|
+
@was_truncated
|
|
162
172
|
end
|
|
163
173
|
|
|
164
174
|
#Should we display the link tag?
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
module Kaminari
|
|
4
4
|
module Helpers
|
|
5
|
-
PARAM_KEY_EXCEPT_LIST = [:authenticity_token, :commit, :utf8, :_method, :script_name, :original_script_name
|
|
5
|
+
PARAM_KEY_EXCEPT_LIST = [:authenticity_token, :commit, :utf8, :_method, :script_name, :original_script_name,
|
|
6
|
+
:subdomain, :domain, :tld_length, :host, :port, :protocol, :anchor, :trailing_slash, :params, :path_params].freeze
|
|
6
7
|
|
|
7
8
|
# A tag stands for an HTML tag inside the paginator.
|
|
8
9
|
# Basically, a tag has its own partial template file, so every tag can be
|
|
@@ -13,60 +14,128 @@ module Kaminari
|
|
|
13
14
|
# class, so _tag partial is not needed).
|
|
14
15
|
# e.g.) PrevLink -> app/views/kaminari/_prev_link.html.erb
|
|
15
16
|
#
|
|
16
|
-
# When no matching
|
|
17
|
+
# When no matching templates were found in your app, the engine's pre
|
|
17
18
|
# installed template will be used.
|
|
18
19
|
# e.g.) Paginator -> $GEM_HOME/kaminari-x.x.x/app/views/kaminari/_paginator.html.erb
|
|
19
20
|
class Tag
|
|
20
|
-
|
|
21
|
+
# A page number that is unlikely to appear in any URL, which stands in for the actual page number in the cached URL
|
|
22
|
+
PAGE_PLACEHOLDER = rand(10**17...10**18)
|
|
23
|
+
|
|
24
|
+
def initialize(template, params: nil, param_name: nil, theme: nil, views_prefix: nil, internal_params: nil, internal_url_cache: nil, internal_partial_cache: nil, **options) #:nodoc:
|
|
21
25
|
@template, @theme, @views_prefix, @options = template, theme, views_prefix, options
|
|
22
26
|
@param_name = param_name || Kaminari.config.param_name
|
|
23
|
-
@
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
@url_cache, @partial_cache = internal_url_cache, internal_partial_cache
|
|
28
|
+
|
|
29
|
+
if internal_params
|
|
30
|
+
@params = internal_params
|
|
31
|
+
else
|
|
32
|
+
@params = template.params
|
|
33
|
+
# @params in Rails 5 no longer inherits from Hash
|
|
34
|
+
@params = if @params.respond_to?(:to_unsafe_h)
|
|
35
|
+
@params.to_unsafe_h
|
|
36
|
+
else
|
|
37
|
+
@params.with_indifferent_access
|
|
38
|
+
end
|
|
39
|
+
@params.except!(*PARAM_KEY_EXCEPT_LIST)
|
|
40
|
+
@params.merge! params if params
|
|
41
|
+
end
|
|
29
42
|
end
|
|
30
43
|
|
|
31
44
|
def to_s(locals = {}) #:nodoc:
|
|
32
|
-
formats =
|
|
33
|
-
@
|
|
45
|
+
formats = @template.respond_to?(:formats) ? @template.formats : Array(@template.params[:format])
|
|
46
|
+
if @partial_cache && formats.include?(:html) && @template.respond_to?(:lookup_context)
|
|
47
|
+
render_cached_partial @options.merge(locals)
|
|
48
|
+
else
|
|
49
|
+
formats += [:html] unless formats.include? :html
|
|
50
|
+
@template.render partial: partial_path, locals: @options.merge(locals), formats: formats
|
|
51
|
+
end
|
|
34
52
|
end
|
|
35
53
|
|
|
36
54
|
def page_url_for(page)
|
|
55
|
+
@url_cache ? cached_page_url_for(page.to_i) : generate_page_url(page)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
# Looking up a partial template is costly, so the paginator looks up each partial only once, and then renders the
|
|
61
|
+
# template directly in the same way as `render partial:` does.
|
|
62
|
+
# This is done only when the formats already include :html, which means the formats that `to_s` would pass to
|
|
63
|
+
# `render` are the same as the current ones, and so finding and rendering the template doesn't depend on the formats.
|
|
64
|
+
def render_cached_partial(locals)
|
|
65
|
+
path, keys = partial_path, locals.keys
|
|
66
|
+
cached_keys, template = @partial_cache[path]
|
|
67
|
+
unless template && (cached_keys == keys)
|
|
68
|
+
template = @template.lookup_context.find_template(path, [], true, keys)
|
|
69
|
+
@partial_cache[path] = [keys, template]
|
|
70
|
+
end
|
|
71
|
+
# `render partial:` in Action View 4 also puts the partial name into local_assigns (e.g. {gap: nil, ...})
|
|
72
|
+
if ActionView::VERSION::MAJOR < 5
|
|
73
|
+
name = File.basename(path).to_sym
|
|
74
|
+
locals[name] = nil unless locals.key? name
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
ActiveSupport::Notifications.instrument('render_partial.action_view', identifier: template.identifier, layout: nil, locals: locals) do
|
|
78
|
+
template.render(@template, locals) {|*name| @template._layout_for(*name) }
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def generate_page_url(page)
|
|
37
83
|
params = params_for(page)
|
|
38
84
|
params[:only_path] = true
|
|
39
85
|
@template.url_for params
|
|
40
86
|
end
|
|
41
87
|
|
|
42
|
-
|
|
88
|
+
# Generating URLs is costly, so the paginator generates the URL only once with a placeholder page number,
|
|
89
|
+
# and then builds the URL for each page by replacing the placeholder
|
|
90
|
+
def cached_page_url_for(page)
|
|
91
|
+
@url_cache.fetch(page) do
|
|
92
|
+
url_template = @url_cache[:url_template]
|
|
93
|
+
@url_cache[page] = if url_template && (page > 1)
|
|
94
|
+
url_template.sub(PAGE_PLACEHOLDER.to_s, page.to_s)
|
|
95
|
+
else
|
|
96
|
+
generate_page_url(page).tap {|url| build_url_template(page, url) if url_template.nil? && (page > 1) }
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
43
100
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
# to: {other: "params", page: nil}
|
|
52
|
-
# (when @param_name == "page")
|
|
53
|
-
#
|
|
54
|
-
# from: {other: "params", user: {name: "yuki", page: 1}}
|
|
55
|
-
# to: {other: "params", user: {name: "yuki", page: nil}}
|
|
56
|
-
# (when @param_name == "user[page]")
|
|
57
|
-
@param_name.to_s.scan(/[\w\.]+/)[0..-2].inject(page_params){|h, k| h[k] }[$&] = nil
|
|
101
|
+
# Use the URL with the placeholder only when it builds exactly the same URL as url_for does.
|
|
102
|
+
# Otherwise (e.g. when the routes constrain the page number), fall back to calling url_for for each page.
|
|
103
|
+
def build_url_template(page, url)
|
|
104
|
+
url_template = begin
|
|
105
|
+
generate_page_url PAGE_PLACEHOLDER
|
|
106
|
+
rescue StandardError
|
|
107
|
+
nil
|
|
58
108
|
end
|
|
109
|
+
@url_cache[:url_template] = url_template && (url_template.scan(PAGE_PLACEHOLDER.to_s).size == 1) && (url_template.sub(PAGE_PLACEHOLDER.to_s, page.to_s) == url) ? url_template : false
|
|
110
|
+
end
|
|
59
111
|
|
|
60
|
-
|
|
112
|
+
def params_for(page)
|
|
113
|
+
if (@param_name == :page) || !@param_name.to_s.include?('[')
|
|
114
|
+
page_val = !Kaminari.config.params_on_first_page && (page <= 1) ? nil : page
|
|
115
|
+
@params[@param_name] = page_val
|
|
116
|
+
@params
|
|
117
|
+
else
|
|
118
|
+
page_params = Rack::Utils.parse_nested_query("#{@param_name}=#{page}")
|
|
119
|
+
page_params = @params.deep_merge(page_params)
|
|
120
|
+
|
|
121
|
+
if !Kaminari.config.params_on_first_page && (page <= 1)
|
|
122
|
+
# This converts a hash:
|
|
123
|
+
# from: {other: "params", page: 1}
|
|
124
|
+
# to: {other: "params", page: nil}
|
|
125
|
+
# (when @param_name == "page")
|
|
126
|
+
#
|
|
127
|
+
# from: {other: "params", user: {name: "yuki", page: 1}}
|
|
128
|
+
# to: {other: "params", user: {name: "yuki", page: nil}}
|
|
129
|
+
# (when @param_name == "user[page]")
|
|
130
|
+
@param_name.to_s.scan(/[\w.]+/)[0..-2].inject(page_params){|h, k| h[k] }[$&] = nil
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
page_params
|
|
134
|
+
end
|
|
61
135
|
end
|
|
62
136
|
|
|
63
137
|
def partial_path
|
|
64
|
-
|
|
65
|
-
@views_prefix,
|
|
66
|
-
"kaminari",
|
|
67
|
-
@theme,
|
|
68
|
-
self.class.name.demodulize.underscore
|
|
69
|
-
].compact.join("/")
|
|
138
|
+
"#{@views_prefix}/kaminari/#{@theme}/#{self.class.name.demodulize.underscore}".gsub('//', '/')
|
|
70
139
|
end
|
|
71
140
|
end
|
|
72
141
|
|
|
@@ -124,7 +193,7 @@ module Kaminari
|
|
|
124
193
|
# params in Rails 5 may not be a Hash either,
|
|
125
194
|
# so it must be converted to a Hash to be merged into @params
|
|
126
195
|
if params && params.respond_to?(:to_unsafe_h)
|
|
127
|
-
|
|
196
|
+
Kaminari.deprecator.warn 'Explicitly passing params to helpers could be omitted.'
|
|
128
197
|
params = params.to_unsafe_h
|
|
129
198
|
end
|
|
130
199
|
|
|
@@ -145,7 +214,7 @@ module Kaminari
|
|
|
145
214
|
# params in Rails 5 may not be a Hash either,
|
|
146
215
|
# so it must be converted to a Hash to be merged into @params
|
|
147
216
|
if params && params.respond_to?(:to_unsafe_h)
|
|
148
|
-
|
|
217
|
+
Kaminari.deprecator.warn 'Explicitly passing params to helpers could be omitted.'
|
|
149
218
|
params = params.to_unsafe_h
|
|
150
219
|
end
|
|
151
220
|
|
|
@@ -41,13 +41,19 @@ module Kaminari
|
|
|
41
41
|
# items at the specified "page"
|
|
42
42
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
|
43
43
|
def #{Kaminari.config.page_method_name}(num = 1)
|
|
44
|
+
num = num.respond_to?(:to_i) ? num.to_i : 1
|
|
44
45
|
offset(limit_value * ((num = num.to_i - 1) < 0 ? 0 : num))
|
|
45
46
|
end
|
|
46
47
|
RUBY
|
|
47
48
|
|
|
48
49
|
# returns another chunk of the original array
|
|
49
50
|
def limit(num)
|
|
50
|
-
|
|
51
|
+
spawn limit: num, offset: @_offset_value
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# overridden by Kaminari::PageScopeMethods once paginated
|
|
55
|
+
def paginated?
|
|
56
|
+
false
|
|
51
57
|
end
|
|
52
58
|
|
|
53
59
|
# total item numbers of the original array
|
|
@@ -57,7 +63,17 @@ module Kaminari
|
|
|
57
63
|
|
|
58
64
|
# returns another chunk of the original array
|
|
59
65
|
def offset(num)
|
|
60
|
-
|
|
66
|
+
spawn limit: @_limit_value, offset: num
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
# Builds another chunk of the original array, carrying over the per page settings given to this one
|
|
72
|
+
def spawn(limit:, offset:)
|
|
73
|
+
self.class.new(@_original_array, limit: limit, offset: offset, total_count: @_total_count, padding: @_padding).tap do |array|
|
|
74
|
+
array.instance_variable_set :@_per, @_per if defined?(@_per)
|
|
75
|
+
array.instance_variable_set :@_max_per_page, @_max_per_page if defined?(@_max_per_page)
|
|
76
|
+
end
|
|
61
77
|
end
|
|
62
78
|
end
|
|
63
79
|
|
|
@@ -6,29 +6,31 @@ module Kaminari
|
|
|
6
6
|
# Model.page(3).per(10)
|
|
7
7
|
def per(num, max_per_page: nil)
|
|
8
8
|
max_per_page ||= ((defined?(@_max_per_page) && @_max_per_page) || self.max_per_page)
|
|
9
|
-
|
|
10
|
-
if (n = num.to_i) < 0 || !(
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
# ignore a negative or a non-numeric value, and keep the current per value
|
|
10
|
+
return self if (n = num.to_i) < 0 || !(/\A\d/ =~ num.to_s)
|
|
11
|
+
|
|
12
|
+
per_value = n
|
|
13
|
+
if n.zero?
|
|
13
14
|
limit(n)
|
|
14
|
-
elsif max_per_page && (max_per_page < n)
|
|
15
|
-
limit(max_per_page).offset(offset_value / limit_value * max_per_page)
|
|
16
15
|
else
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
n = max_per_page if max_per_page && (max_per_page < n)
|
|
17
|
+
padding_value = (defined?(@_padding) && @_padding) || 0
|
|
18
|
+
# the current page is unknown after per(0), so go back to the first page
|
|
19
|
+
page_offset = limit_value.zero? ? 0 : (offset_value - padding_value) / limit_value * n
|
|
20
|
+
limit_and_offset n, page_offset + padding_value
|
|
21
|
+
end.tap {|scope| scope.instance_variable_set :@_per, per_value }
|
|
19
22
|
end
|
|
20
23
|
|
|
21
24
|
def max_paginates_per(new_max_per_page)
|
|
22
|
-
@
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
per((defined?(@_per) && @_per) || default_per_page, max_per_page: new_max_per_page).tap do |scope|
|
|
26
|
+
scope.instance_variable_set :@_max_per_page, new_max_per_page
|
|
27
|
+
end
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
def padding(num)
|
|
28
31
|
num = num.to_i
|
|
29
32
|
raise ArgumentError, "padding must not be negative" if num < 0
|
|
30
|
-
|
|
31
|
-
offset(offset_value + @_padding)
|
|
33
|
+
offset(offset_value + num).tap {|scope| scope.instance_variable_set :@_padding, num }
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
# Total number of pages
|
|
@@ -56,8 +58,8 @@ module Kaminari
|
|
|
56
58
|
|
|
57
59
|
# Current per-page number
|
|
58
60
|
def current_per_page
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
Kaminari.deprecator.warn '#current_per_page is deprecated and will be removed in the next major ' \
|
|
62
|
+
'version. Please use #limit_value instead.'
|
|
61
63
|
|
|
62
64
|
limit_value
|
|
63
65
|
# (defined?(@_per) && @_per) || default_per_page
|
|
@@ -87,5 +89,16 @@ module Kaminari
|
|
|
87
89
|
def out_of_range?
|
|
88
90
|
current_page > total_pages
|
|
89
91
|
end
|
|
92
|
+
|
|
93
|
+
def paginated?
|
|
94
|
+
limit_value.present?
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
private
|
|
98
|
+
|
|
99
|
+
# Returns another scope with the given limit and offset
|
|
100
|
+
def limit_and_offset(new_limit, new_offset)
|
|
101
|
+
limit(new_limit).offset(new_offset)
|
|
102
|
+
end
|
|
90
103
|
end
|
|
91
104
|
end
|
metadata
CHANGED
|
@@ -1,113 +1,118 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kaminari-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
|
-
- Akira Matsuda
|
|
8
|
-
autorequire:
|
|
7
|
+
- Akira Matsuda
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
|
-
- !ruby/object:Gem::Dependency
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
- !ruby/object:Gem::
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: bundler
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
-
|
|
17
|
+
- ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: "1.13"
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
-
|
|
25
|
+
- ">="
|
|
26
|
+
- !ruby/object:Gem::Version
|
|
27
|
+
version: "1.13"
|
|
28
|
+
- !ruby/object:Gem::Dependency
|
|
29
|
+
name: rake
|
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
-
|
|
33
|
+
- ">="
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: "10.0"
|
|
36
|
+
type: :development
|
|
37
|
+
prerelease: false
|
|
38
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
39
|
+
requirements:
|
|
40
|
+
-
|
|
41
|
+
- ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: "10.0"
|
|
44
|
+
description: kaminari-core includes pagination logic independent from ORMs and view libraries
|
|
43
45
|
email:
|
|
44
|
-
- ronnie@dio.jp
|
|
46
|
+
- ronnie@dio.jp
|
|
45
47
|
executables: []
|
|
46
48
|
extensions: []
|
|
47
49
|
extra_rdoc_files: []
|
|
48
50
|
files:
|
|
49
|
-
- CHANGELOG.md
|
|
50
|
-
- MIT-LICENSE
|
|
51
|
-
- README.md
|
|
52
|
-
- app/views/kaminari/_first_page.html.erb
|
|
53
|
-
- app/views/kaminari/_first_page.html.haml
|
|
54
|
-
- app/views/kaminari/_first_page.html.slim
|
|
55
|
-
- app/views/kaminari/_gap.html.erb
|
|
56
|
-
- app/views/kaminari/_gap.html.haml
|
|
57
|
-
- app/views/kaminari/_gap.html.slim
|
|
58
|
-
- app/views/kaminari/_last_page.html.erb
|
|
59
|
-
- app/views/kaminari/_last_page.html.haml
|
|
60
|
-
- app/views/kaminari/_last_page.html.slim
|
|
61
|
-
- app/views/kaminari/_next_page.html.erb
|
|
62
|
-
- app/views/kaminari/_next_page.html.haml
|
|
63
|
-
- app/views/kaminari/_next_page.html.slim
|
|
64
|
-
- app/views/kaminari/_page.html.erb
|
|
65
|
-
- app/views/kaminari/_page.html.haml
|
|
66
|
-
- app/views/kaminari/_page.html.slim
|
|
67
|
-
- app/views/kaminari/_paginator.html.erb
|
|
68
|
-
- app/views/kaminari/_paginator.html.haml
|
|
69
|
-
- app/views/kaminari/_paginator.html.slim
|
|
70
|
-
- app/views/kaminari/_prev_page.html.erb
|
|
71
|
-
- app/views/kaminari/_prev_page.html.haml
|
|
72
|
-
- app/views/kaminari/_prev_page.html.slim
|
|
73
|
-
- config/locales/kaminari.yml
|
|
74
|
-
- kaminari-core.gemspec
|
|
75
|
-
- lib/generators/kaminari/config_generator.rb
|
|
76
|
-
- lib/generators/kaminari/templates/kaminari_config.rb
|
|
77
|
-
- lib/generators/kaminari/views_generator.rb
|
|
78
|
-
- lib/kaminari/config.rb
|
|
79
|
-
- lib/kaminari/core.rb
|
|
80
|
-
- lib/kaminari/core/version.rb
|
|
81
|
-
- lib/kaminari/engine.rb
|
|
82
|
-
- lib/kaminari/exceptions.rb
|
|
83
|
-
- lib/kaminari/helpers/helper_methods.rb
|
|
84
|
-
- lib/kaminari/helpers/paginator.rb
|
|
85
|
-
- lib/kaminari/helpers/tags.rb
|
|
86
|
-
- lib/kaminari/models/array_extension.rb
|
|
87
|
-
- lib/kaminari/models/configuration_methods.rb
|
|
88
|
-
- lib/kaminari/models/page_scope_methods.rb
|
|
89
|
-
- lib/kaminari/railtie.rb
|
|
90
|
-
homepage: https://github.com/kaminari/kaminari
|
|
51
|
+
- CHANGELOG.md
|
|
52
|
+
- MIT-LICENSE
|
|
53
|
+
- README.md
|
|
54
|
+
- app/views/kaminari/_first_page.html.erb
|
|
55
|
+
- app/views/kaminari/_first_page.html.haml
|
|
56
|
+
- app/views/kaminari/_first_page.html.slim
|
|
57
|
+
- app/views/kaminari/_gap.html.erb
|
|
58
|
+
- app/views/kaminari/_gap.html.haml
|
|
59
|
+
- app/views/kaminari/_gap.html.slim
|
|
60
|
+
- app/views/kaminari/_last_page.html.erb
|
|
61
|
+
- app/views/kaminari/_last_page.html.haml
|
|
62
|
+
- app/views/kaminari/_last_page.html.slim
|
|
63
|
+
- app/views/kaminari/_next_page.html.erb
|
|
64
|
+
- app/views/kaminari/_next_page.html.haml
|
|
65
|
+
- app/views/kaminari/_next_page.html.slim
|
|
66
|
+
- app/views/kaminari/_page.html.erb
|
|
67
|
+
- app/views/kaminari/_page.html.haml
|
|
68
|
+
- app/views/kaminari/_page.html.slim
|
|
69
|
+
- app/views/kaminari/_paginator.html.erb
|
|
70
|
+
- app/views/kaminari/_paginator.html.haml
|
|
71
|
+
- app/views/kaminari/_paginator.html.slim
|
|
72
|
+
- app/views/kaminari/_prev_page.html.erb
|
|
73
|
+
- app/views/kaminari/_prev_page.html.haml
|
|
74
|
+
- app/views/kaminari/_prev_page.html.slim
|
|
75
|
+
- config/locales/kaminari.yml
|
|
76
|
+
- kaminari-core.gemspec
|
|
77
|
+
- lib/generators/kaminari/config_generator.rb
|
|
78
|
+
- lib/generators/kaminari/templates/kaminari_config.rb
|
|
79
|
+
- lib/generators/kaminari/views_generator.rb
|
|
80
|
+
- lib/kaminari/config.rb
|
|
81
|
+
- lib/kaminari/core.rb
|
|
82
|
+
- lib/kaminari/core/version.rb
|
|
83
|
+
- lib/kaminari/engine.rb
|
|
84
|
+
- lib/kaminari/exceptions.rb
|
|
85
|
+
- lib/kaminari/helpers/helper_methods.rb
|
|
86
|
+
- lib/kaminari/helpers/paginator.rb
|
|
87
|
+
- lib/kaminari/helpers/tags.rb
|
|
88
|
+
- lib/kaminari/models/array_extension.rb
|
|
89
|
+
- lib/kaminari/models/configuration_methods.rb
|
|
90
|
+
- lib/kaminari/models/page_scope_methods.rb
|
|
91
|
+
- lib/kaminari/railtie.rb
|
|
92
|
+
homepage: "https://github.com/kaminari/kaminari"
|
|
91
93
|
licenses:
|
|
92
|
-
- MIT
|
|
93
|
-
metadata:
|
|
94
|
-
|
|
94
|
+
- MIT
|
|
95
|
+
metadata:
|
|
96
|
+
changelog_uri: "https://github.com/kaminari/kaminari/blob/master/CHANGELOG.md"
|
|
97
|
+
source_code_uri: "https://github.com/kaminari/kaminari/tree/master/kaminari-core"
|
|
98
|
+
rubygems_mfa_required: "true"
|
|
95
99
|
rdoc_options: []
|
|
96
100
|
require_paths:
|
|
97
|
-
- lib
|
|
101
|
+
- lib
|
|
98
102
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
99
103
|
requirements:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
104
|
+
-
|
|
105
|
+
- ">="
|
|
106
|
+
- !ruby/object:Gem::Version
|
|
107
|
+
version: 2.0.0
|
|
103
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
109
|
requirements:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
110
|
+
-
|
|
111
|
+
- ">="
|
|
112
|
+
- !ruby/object:Gem::Version
|
|
113
|
+
version: "0"
|
|
108
114
|
requirements: []
|
|
109
|
-
rubygems_version:
|
|
110
|
-
signing_key:
|
|
115
|
+
rubygems_version: 4.1.0.beta2
|
|
111
116
|
specification_version: 4
|
|
112
117
|
summary: Kaminari's core pagination library
|
|
113
118
|
test_files: []
|