kaminari-core 1.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +21 -0
- data/README.md +31 -0
- data/app/views/kaminari/_first_page.html.erb +11 -0
- data/app/views/kaminari/_first_page.html.haml +9 -0
- data/app/views/kaminari/_first_page.html.slim +10 -0
- data/app/views/kaminari/_gap.html.erb +8 -0
- data/app/views/kaminari/_gap.html.haml +8 -0
- data/app/views/kaminari/_gap.html.slim +9 -0
- data/app/views/kaminari/_last_page.html.erb +11 -0
- data/app/views/kaminari/_last_page.html.haml +9 -0
- data/app/views/kaminari/_last_page.html.slim +10 -0
- data/app/views/kaminari/_next_page.html.erb +11 -0
- data/app/views/kaminari/_next_page.html.haml +9 -0
- data/app/views/kaminari/_next_page.html.slim +10 -0
- data/app/views/kaminari/_page.html.erb +12 -0
- data/app/views/kaminari/_page.html.haml +10 -0
- data/app/views/kaminari/_page.html.slim +11 -0
- data/app/views/kaminari/_paginator.html.erb +25 -0
- data/app/views/kaminari/_paginator.html.haml +18 -0
- data/app/views/kaminari/_paginator.html.slim +19 -0
- data/app/views/kaminari/_prev_page.html.erb +11 -0
- data/app/views/kaminari/_prev_page.html.haml +9 -0
- data/app/views/kaminari/_prev_page.html.slim +10 -0
- data/config/locales/kaminari.yml +23 -0
- data/kaminari-core.gemspec +23 -0
- data/lib/generators/kaminari/config_generator.rb +18 -0
- data/lib/generators/kaminari/templates/kaminari_config.rb +12 -0
- data/lib/generators/kaminari/views_generator.rb +134 -0
- data/lib/kaminari/config.rb +28 -0
- data/lib/kaminari/core.rb +23 -0
- data/lib/kaminari/core/version.rb +6 -0
- data/lib/kaminari/engine.rb +5 -0
- data/lib/kaminari/exceptions.rb +4 -0
- data/lib/kaminari/helpers/helper_methods.rb +169 -0
- data/lib/kaminari/helpers/paginator.rb +189 -0
- data/lib/kaminari/helpers/tags.rb +137 -0
- data/lib/kaminari/models/array_extension.rb +72 -0
- data/lib/kaminari/models/configuration_methods.rb +57 -0
- data/lib/kaminari/models/page_scope_methods.rb +80 -0
- data/lib/kaminari/railtie.rb +8 -0
- metadata +113 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/configurable'
|
3
|
+
|
4
|
+
module Kaminari
|
5
|
+
# Configures global settings for Kaminari
|
6
|
+
# Kaminari.configure do |config|
|
7
|
+
# config.default_per_page = 10
|
8
|
+
# end
|
9
|
+
include ActiveSupport::Configurable
|
10
|
+
|
11
|
+
config.instance_eval do
|
12
|
+
self.default_per_page = 25
|
13
|
+
self.max_per_page = nil
|
14
|
+
self.window = 4
|
15
|
+
self.outer_window = 0
|
16
|
+
self.left = 0
|
17
|
+
self.right = 0
|
18
|
+
self.page_method_name = :page
|
19
|
+
self.param_name = :page
|
20
|
+
self.max_pages = nil
|
21
|
+
self.params_on_first_page = false
|
22
|
+
|
23
|
+
# If param_name was given as a callable object, call it when returning
|
24
|
+
def param_name
|
25
|
+
self[:param_name].respond_to?(:call) ? self[:param_name].call : self[:param_name]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Kaminari
|
3
|
+
end
|
4
|
+
|
5
|
+
# load Rails/Railtie
|
6
|
+
begin
|
7
|
+
require 'rails'
|
8
|
+
rescue LoadError
|
9
|
+
#do nothing
|
10
|
+
end
|
11
|
+
|
12
|
+
# load Kaminari components
|
13
|
+
require 'kaminari/config'
|
14
|
+
require 'kaminari/exceptions'
|
15
|
+
require 'kaminari/helpers/paginator'
|
16
|
+
require 'kaminari/models/page_scope_methods'
|
17
|
+
require 'kaminari/models/configuration_methods'
|
18
|
+
require 'kaminari/models/array_extension'
|
19
|
+
|
20
|
+
if defined? ::Rails::Railtie
|
21
|
+
require 'kaminari/railtie'
|
22
|
+
require 'kaminari/engine'
|
23
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
module Kaminari
|
2
|
+
module Helpers
|
3
|
+
module HelperMethods
|
4
|
+
# A helper that renders the pagination links.
|
5
|
+
#
|
6
|
+
# <%= paginate @articles %>
|
7
|
+
#
|
8
|
+
# ==== Options
|
9
|
+
# * <tt>:window</tt> - The "inner window" size (4 by default).
|
10
|
+
# * <tt>:outer_window</tt> - The "outer window" size (0 by default).
|
11
|
+
# * <tt>:left</tt> - The "left outer window" size (0 by default).
|
12
|
+
# * <tt>:right</tt> - The "right outer window" size (0 by default).
|
13
|
+
# * <tt>:params</tt> - url_for parameters for the links (:controller, :action, etc.)
|
14
|
+
# * <tt>:param_name</tt> - parameter name for page number in the links (:page by default)
|
15
|
+
# * <tt>:remote</tt> - Ajax? (false by default)
|
16
|
+
# * <tt>:paginator_class</tt> - Specify a custom Paginator (Kaminari::Helpers::Paginator by default)
|
17
|
+
# * <tt>:template</tt> - Specify a custom template renderer for rendering the Paginator (receiver by default)
|
18
|
+
# * <tt>:ANY_OTHER_VALUES</tt> - Any other hash key & values would be directly passed into each tag as :locals value.
|
19
|
+
def paginate(scope, paginator_class: Kaminari::Helpers::Paginator, template: nil, **options)
|
20
|
+
options[:total_pages] ||= scope.total_pages
|
21
|
+
options.reverse_merge! current_page: scope.current_page, per_page: scope.limit_value, remote: false
|
22
|
+
|
23
|
+
paginator = paginator_class.new (template || self), options
|
24
|
+
paginator.to_s
|
25
|
+
end
|
26
|
+
|
27
|
+
# A simple "Twitter like" pagination link that creates a link to the previous page.
|
28
|
+
#
|
29
|
+
# ==== Examples
|
30
|
+
# Basic usage:
|
31
|
+
#
|
32
|
+
# <%= link_to_previous_page @items, 'Previous Page' %>
|
33
|
+
#
|
34
|
+
# Ajax:
|
35
|
+
#
|
36
|
+
# <%= link_to_previous_page @items, 'Previous Page', remote: true %>
|
37
|
+
#
|
38
|
+
# By default, it renders nothing if there are no more results on the previous page.
|
39
|
+
# You can customize this output by passing a block.
|
40
|
+
#
|
41
|
+
# <%= link_to_previous_page @users, 'Previous Page' do %>
|
42
|
+
# <span>At the Beginning</span>
|
43
|
+
# <% end %>
|
44
|
+
def link_to_previous_page(scope, name, **options)
|
45
|
+
prev_page = path_to_prev_page(scope, options)
|
46
|
+
|
47
|
+
options.except! :params, :param_name
|
48
|
+
options[:rel] ||= 'prev'
|
49
|
+
|
50
|
+
link_to_if prev_page, name, prev_page, options do
|
51
|
+
yield if block_given?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
alias link_to_prev_page link_to_previous_page
|
55
|
+
|
56
|
+
# A simple "Twitter like" pagination link that creates a link to the next page.
|
57
|
+
#
|
58
|
+
# ==== Examples
|
59
|
+
# Basic usage:
|
60
|
+
#
|
61
|
+
# <%= link_to_next_page @items, 'Next Page' %>
|
62
|
+
#
|
63
|
+
# Ajax:
|
64
|
+
#
|
65
|
+
# <%= link_to_next_page @items, 'Next Page', remote: true %>
|
66
|
+
#
|
67
|
+
# By default, it renders nothing if there are no more results on the next page.
|
68
|
+
# You can customize this output by passing a block.
|
69
|
+
#
|
70
|
+
# <%= link_to_next_page @users, 'Next Page' do %>
|
71
|
+
# <span>No More Pages</span>
|
72
|
+
# <% end %>
|
73
|
+
def link_to_next_page(scope, name, **options)
|
74
|
+
next_page = path_to_next_page(scope, options)
|
75
|
+
|
76
|
+
options.except! :params, :param_name
|
77
|
+
options[:rel] ||= 'next'
|
78
|
+
|
79
|
+
link_to_if next_page, name, next_page, options do
|
80
|
+
yield if block_given?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Renders a helpful message with numbers of displayed vs. total entries.
|
85
|
+
# Ported from mislav/will_paginate
|
86
|
+
#
|
87
|
+
# ==== Examples
|
88
|
+
# Basic usage:
|
89
|
+
#
|
90
|
+
# <%= page_entries_info @posts %>
|
91
|
+
# #-> Displaying posts 6 - 10 of 26 in total
|
92
|
+
#
|
93
|
+
# By default, the message will use the humanized class name of objects
|
94
|
+
# in collection: for instance, "project types" for ProjectType models.
|
95
|
+
# The namespace will be cutted out and only the last name will be used.
|
96
|
+
# Override this with the <tt>:entry_name</tt> parameter:
|
97
|
+
#
|
98
|
+
# <%= page_entries_info @posts, entry_name: 'item' %>
|
99
|
+
# #-> Displaying items 6 - 10 of 26 in total
|
100
|
+
def page_entries_info(collection, entry_name: nil)
|
101
|
+
entry_name = if entry_name
|
102
|
+
entry_name.pluralize(collection.size)
|
103
|
+
else
|
104
|
+
collection.entry_name(count: collection.size).downcase
|
105
|
+
end
|
106
|
+
|
107
|
+
if collection.total_pages < 2
|
108
|
+
t('helpers.page_entries_info.one_page.display_entries', entry_name: entry_name, count: collection.total_count)
|
109
|
+
else
|
110
|
+
t('helpers.page_entries_info.more_pages.display_entries', entry_name: entry_name, first: collection.offset_value + 1, last: [collection.offset_value + collection.limit_value, collection.total_count].min, total: collection.total_count)
|
111
|
+
end.html_safe
|
112
|
+
end
|
113
|
+
|
114
|
+
# Renders rel="next" and rel="prev" links to be used in the head.
|
115
|
+
#
|
116
|
+
# ==== Examples
|
117
|
+
# Basic usage:
|
118
|
+
#
|
119
|
+
# In head:
|
120
|
+
# <head>
|
121
|
+
# <title>My Website</title>
|
122
|
+
# <%= yield :head %>
|
123
|
+
# </head>
|
124
|
+
#
|
125
|
+
# Somewhere in body:
|
126
|
+
# <% content_for :head do %>
|
127
|
+
# <%= rel_next_prev_link_tags @items %>
|
128
|
+
# <% end %>
|
129
|
+
#
|
130
|
+
# #-> <link rel="next" href="/items/page/3" /><link rel="prev" href="/items/page/1" />
|
131
|
+
#
|
132
|
+
def rel_next_prev_link_tags(scope, options = {})
|
133
|
+
next_page = path_to_next_page(scope, options)
|
134
|
+
prev_page = path_to_prev_page(scope, options)
|
135
|
+
|
136
|
+
output = String.new
|
137
|
+
output << tag(:link, rel: "next", href: next_page) if next_page
|
138
|
+
output << tag(:link, rel: "prev", href: prev_page) if prev_page
|
139
|
+
output.html_safe
|
140
|
+
end
|
141
|
+
|
142
|
+
# A helper that calculates the path to the next page.
|
143
|
+
#
|
144
|
+
# ==== Examples
|
145
|
+
# Basic usage:
|
146
|
+
#
|
147
|
+
# <%= path_to_next_page @items %>
|
148
|
+
# #-> /items?page=2
|
149
|
+
#
|
150
|
+
# It will return `nil` if there is no next page.
|
151
|
+
def path_to_next_page(scope, options = {})
|
152
|
+
Kaminari::Helpers::NextPage.new(self, options.reverse_merge(current_page: scope.current_page)).url if scope.next_page
|
153
|
+
end
|
154
|
+
|
155
|
+
# A helper that calculates the path to the previous page.
|
156
|
+
#
|
157
|
+
# ==== Examples
|
158
|
+
# Basic usage:
|
159
|
+
#
|
160
|
+
# <%= path_to_prev_page @items %>
|
161
|
+
# #-> /items
|
162
|
+
#
|
163
|
+
# It will return `nil` if there is no previous page.
|
164
|
+
def path_to_prev_page(scope, options = {})
|
165
|
+
Kaminari::Helpers::PrevPage.new(self, options.reverse_merge(current_page: scope.current_page)).url if scope.prev_page
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,189 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/inflector'
|
3
|
+
require 'kaminari/helpers/tags'
|
4
|
+
|
5
|
+
module Kaminari
|
6
|
+
module Helpers
|
7
|
+
# The main container tag
|
8
|
+
class Paginator < Tag
|
9
|
+
def initialize(template, window: nil, outer_window: nil, left: nil, right: nil, inner_window: nil, **options) #:nodoc:
|
10
|
+
outer_window ||= Kaminari.config.outer_window
|
11
|
+
left ||= Kaminari.config.left
|
12
|
+
right ||= Kaminari.config.right
|
13
|
+
@window_options = {window: window || inner_window || Kaminari.config.window, left: left.zero? ? outer_window : left, right: right.zero? ? outer_window : right}
|
14
|
+
|
15
|
+
@template, @options, @theme, @views_prefix, @last = template, options, options[:theme], options[:views_prefix], nil
|
16
|
+
@window_options.merge! @options
|
17
|
+
@window_options[:current_page] = @options[:current_page] = PageProxy.new(@window_options, @options[:current_page], nil)
|
18
|
+
|
19
|
+
#XXX Using parent template's buffer class for rendering each partial here. This might cause problems if the handler mismatches
|
20
|
+
@output_buffer = if defined?(::ActionView::OutputBuffer)
|
21
|
+
::ActionView::OutputBuffer.new
|
22
|
+
elsif template.instance_variable_get(:@output_buffer)
|
23
|
+
template.instance_variable_get(:@output_buffer).class.new
|
24
|
+
else
|
25
|
+
ActiveSupport::SafeBuffer.new
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# render given block as a view template
|
30
|
+
def render(&block)
|
31
|
+
instance_eval(&block) if @options[:total_pages] > 1
|
32
|
+
@output_buffer
|
33
|
+
end
|
34
|
+
|
35
|
+
# enumerate each page providing PageProxy object as the block parameter
|
36
|
+
# Because of performance reason, this doesn't actually enumerate all pages but pages that are seemingly relevant to the paginator.
|
37
|
+
# "Relevant" pages are:
|
38
|
+
# * pages inside the left outer window plus one for showing the gap tag
|
39
|
+
# * pages inside the inner window plus one on the left plus one on the right for showing the gap tags
|
40
|
+
# * pages inside the right outer window plus one for showing the gap tag
|
41
|
+
def each_relevant_page
|
42
|
+
return to_enum(:each_relevant_page) unless block_given?
|
43
|
+
|
44
|
+
relevant_pages(@window_options).each do |page|
|
45
|
+
yield PageProxy.new(@window_options, page, @last)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
alias each_page each_relevant_page
|
49
|
+
|
50
|
+
def relevant_pages(options)
|
51
|
+
left_window_plus_one = [*1..options[:left] + 1]
|
52
|
+
right_window_plus_one = [*options[:total_pages] - options[:right]..options[:total_pages]]
|
53
|
+
inside_window_plus_each_sides = [*options[:current_page] - options[:window] - 1..options[:current_page] + options[:window] + 1]
|
54
|
+
|
55
|
+
(left_window_plus_one | inside_window_plus_each_sides | right_window_plus_one).sort.reject {|x| (x < 1) || (x > options[:total_pages])}
|
56
|
+
end
|
57
|
+
private :relevant_pages
|
58
|
+
|
59
|
+
def page_tag(page)
|
60
|
+
@last = Page.new @template, @options.merge(page: page)
|
61
|
+
end
|
62
|
+
|
63
|
+
%w[first_page prev_page next_page last_page gap].each do |tag|
|
64
|
+
eval <<-DEF, nil, __FILE__, __LINE__ + 1
|
65
|
+
def #{tag}_tag
|
66
|
+
@last = #{tag.classify}.new @template, @options
|
67
|
+
end
|
68
|
+
DEF
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_s #:nodoc:
|
72
|
+
Thread.current[:kaminari_rendering] = true
|
73
|
+
super @window_options.merge paginator: self
|
74
|
+
ensure
|
75
|
+
Thread.current[:kaminari_rendering] = false
|
76
|
+
end
|
77
|
+
|
78
|
+
# delegates view helper methods to @template
|
79
|
+
def method_missing(name, *args, &block)
|
80
|
+
@template.respond_to?(name) ? @template.send(name, *args, &block) : super
|
81
|
+
end
|
82
|
+
private :method_missing
|
83
|
+
|
84
|
+
# Wraps a "page number" and provides some utility methods
|
85
|
+
class PageProxy
|
86
|
+
include Comparable
|
87
|
+
|
88
|
+
def initialize(options, page, last) #:nodoc:
|
89
|
+
@options, @page, @last = options, page, last
|
90
|
+
end
|
91
|
+
|
92
|
+
# the page number
|
93
|
+
def number
|
94
|
+
@page
|
95
|
+
end
|
96
|
+
|
97
|
+
# current page or not
|
98
|
+
def current?
|
99
|
+
@page == @options[:current_page]
|
100
|
+
end
|
101
|
+
|
102
|
+
# the first page or not
|
103
|
+
def first?
|
104
|
+
@page == 1
|
105
|
+
end
|
106
|
+
|
107
|
+
# the last page or not
|
108
|
+
def last?
|
109
|
+
@page == @options[:total_pages]
|
110
|
+
end
|
111
|
+
|
112
|
+
# the previous page or not
|
113
|
+
def prev?
|
114
|
+
@page == @options[:current_page] - 1
|
115
|
+
end
|
116
|
+
|
117
|
+
# the next page or not
|
118
|
+
def next?
|
119
|
+
@page == @options[:current_page] + 1
|
120
|
+
end
|
121
|
+
|
122
|
+
# relationship with the current page
|
123
|
+
def rel
|
124
|
+
if next?
|
125
|
+
'next'
|
126
|
+
elsif prev?
|
127
|
+
'prev'
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# within the left outer window or not
|
132
|
+
def left_outer?
|
133
|
+
@page <= @options[:left]
|
134
|
+
end
|
135
|
+
|
136
|
+
# within the right outer window or not
|
137
|
+
def right_outer?
|
138
|
+
@options[:total_pages] - @page < @options[:right]
|
139
|
+
end
|
140
|
+
|
141
|
+
# inside the inner window or not
|
142
|
+
def inside_window?
|
143
|
+
(@options[:current_page] - @page).abs <= @options[:window]
|
144
|
+
end
|
145
|
+
|
146
|
+
# Current page is an isolated gap or not
|
147
|
+
def single_gap?
|
148
|
+
((@page == @options[:current_page] - @options[:window] - 1) && (@page == @options[:left] + 1)) ||
|
149
|
+
((@page == @options[:current_page] + @options[:window] + 1) && (@page == @options[:total_pages] - @options[:right]))
|
150
|
+
end
|
151
|
+
|
152
|
+
# The page number exceeds the range of pages or not
|
153
|
+
def out_of_range?
|
154
|
+
@page > @options[:total_pages]
|
155
|
+
end
|
156
|
+
|
157
|
+
# The last rendered tag was "truncated" or not
|
158
|
+
def was_truncated?
|
159
|
+
@last.is_a? Gap
|
160
|
+
end
|
161
|
+
|
162
|
+
#Should we display the link tag?
|
163
|
+
def display_tag?
|
164
|
+
left_outer? || right_outer? || inside_window? || single_gap?
|
165
|
+
end
|
166
|
+
|
167
|
+
def to_i #:nodoc:
|
168
|
+
number
|
169
|
+
end
|
170
|
+
|
171
|
+
def to_s #:nodoc:
|
172
|
+
number.to_s
|
173
|
+
end
|
174
|
+
|
175
|
+
def +(other) #:nodoc:
|
176
|
+
to_i + other.to_i
|
177
|
+
end
|
178
|
+
|
179
|
+
def -(other) #:nodoc:
|
180
|
+
to_i - other.to_i
|
181
|
+
end
|
182
|
+
|
183
|
+
def <=>(other) #:nodoc:
|
184
|
+
to_i <=> other.to_i
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Kaminari
|
3
|
+
module Helpers
|
4
|
+
PARAM_KEY_BLACKLIST = [:authenticity_token, :commit, :utf8, :_method, :script_name].freeze
|
5
|
+
|
6
|
+
# A tag stands for an HTML tag inside the paginator.
|
7
|
+
# Basically, a tag has its own partial template file, so every tag can be
|
8
|
+
# rendered into String using its partial template.
|
9
|
+
#
|
10
|
+
# The template file should be placed in your app/views/kaminari/ directory
|
11
|
+
# with underscored class name (besides the "Tag" class. Tag is an abstract
|
12
|
+
# class, so _tag partial is not needed).
|
13
|
+
# e.g.) PrevLink -> app/views/kaminari/_prev_link.html.erb
|
14
|
+
#
|
15
|
+
# When no matching template were found in your app, the engine's pre
|
16
|
+
# installed template will be used.
|
17
|
+
# e.g.) Paginator -> $GEM_HOME/kaminari-x.x.x/app/views/kaminari/_paginator.html.erb
|
18
|
+
class Tag
|
19
|
+
def initialize(template, params: {}, param_name: nil, theme: nil, views_prefix: nil, **options) #:nodoc:
|
20
|
+
@template, @theme, @views_prefix, @options = template, theme, views_prefix, options
|
21
|
+
@param_name = param_name || Kaminari.config.param_name
|
22
|
+
@params = template.params
|
23
|
+
# @params in Rails 5 no longer inherits from Hash
|
24
|
+
@params = @params.to_unsafe_h if @params.respond_to?(:to_unsafe_h)
|
25
|
+
@params = @params.with_indifferent_access
|
26
|
+
@params.except!(*PARAM_KEY_BLACKLIST)
|
27
|
+
@params.merge! params
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s(locals = {}) #:nodoc:
|
31
|
+
formats = (@template.respond_to?(:formats) ? @template.formats : Array(@template.params[:format])) + [:html]
|
32
|
+
@template.render partial: partial_path, locals: @options.merge(locals), formats: formats
|
33
|
+
end
|
34
|
+
|
35
|
+
def page_url_for(page)
|
36
|
+
params = params_for(page)
|
37
|
+
params[:only_path] = true
|
38
|
+
@template.url_for params
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def params_for(page)
|
44
|
+
page_params = Rack::Utils.parse_nested_query("#{@param_name}=#{page}")
|
45
|
+
page_params = @params.deep_merge(page_params)
|
46
|
+
|
47
|
+
if !Kaminari.config.params_on_first_page && (page <= 1)
|
48
|
+
# This converts a hash:
|
49
|
+
# from: {other: "params", page: 1}
|
50
|
+
# to: {other: "params", page: nil}
|
51
|
+
# (when @param_name == "page")
|
52
|
+
#
|
53
|
+
# from: {other: "params", user: {name: "yuki", page: 1}}
|
54
|
+
# to: {other: "params", user: {name: "yuki", page: nil}}
|
55
|
+
# (when @param_name == "user[page]")
|
56
|
+
@param_name.to_s.scan(/[\w\.]+/)[0..-2].inject(page_params){|h, k| h[k] }[$&] = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
page_params
|
60
|
+
end
|
61
|
+
|
62
|
+
def partial_path
|
63
|
+
[
|
64
|
+
@views_prefix,
|
65
|
+
"kaminari",
|
66
|
+
@theme,
|
67
|
+
self.class.name.demodulize.underscore
|
68
|
+
].compact.join("/")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Tag that contains a link
|
73
|
+
module Link
|
74
|
+
# target page number
|
75
|
+
def page
|
76
|
+
raise 'Override page with the actual page value to be a Page.'
|
77
|
+
end
|
78
|
+
# the link's href
|
79
|
+
def url
|
80
|
+
page_url_for page
|
81
|
+
end
|
82
|
+
def to_s(locals = {}) #:nodoc:
|
83
|
+
locals[:url] = url
|
84
|
+
super locals
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# A page
|
89
|
+
class Page < Tag
|
90
|
+
include Link
|
91
|
+
# target page number
|
92
|
+
def page
|
93
|
+
@options[:page]
|
94
|
+
end
|
95
|
+
def to_s(locals = {}) #:nodoc:
|
96
|
+
locals[:page] = page
|
97
|
+
super locals
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Link with page number that appears at the leftmost
|
102
|
+
class FirstPage < Tag
|
103
|
+
include Link
|
104
|
+
def page #:nodoc:
|
105
|
+
1
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Link with page number that appears at the rightmost
|
110
|
+
class LastPage < Tag
|
111
|
+
include Link
|
112
|
+
def page #:nodoc:
|
113
|
+
@options[:total_pages]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# The "previous" page of the current page
|
118
|
+
class PrevPage < Tag
|
119
|
+
include Link
|
120
|
+
def page #:nodoc:
|
121
|
+
@options[:current_page] - 1
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# The "next" page of the current page
|
126
|
+
class NextPage < Tag
|
127
|
+
include Link
|
128
|
+
def page #:nodoc:
|
129
|
+
@options[:current_page] + 1
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# Non-link tag that stands for skipped pages...
|
134
|
+
class Gap < Tag
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|