1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
|
# frozen_string_literal: true
# Redmine - project management software
# Copyright (C) 2006-2019 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module Redmine
module Pagination
class Paginator
attr_reader :item_count, :per_page, :page, :page_param
def initialize(*args)
if args.first.is_a?(ActionController::Base)
args.shift
ActiveSupport::Deprecation.warn "Paginator no longer takes a controller instance as the first argument. Remove it from #new arguments."
end
item_count, per_page, page, page_param = *args
@item_count = item_count
@per_page = per_page
page = (page || 1).to_i
if page < 1
page = 1
end
@page = page
@page_param = page_param || :page
end
def offset
(page - 1) * per_page
end
def first_page
if item_count > 0
1
end
end
def previous_page
if page > 1
page - 1
end
end
def next_page
if last_item < item_count
page + 1
end
end
def last_page
if item_count > 0
(item_count - 1) / per_page + 1
end
end
def multiple_pages?
per_page < item_count
end
def first_item
item_count == 0 ? 0 : (offset + 1)
end
def last_item
l = first_item + per_page - 1
l > item_count ? item_count : l
end
def linked_pages
pages = []
if item_count > 0
pages += [first_page, page, last_page]
pages += ((page-2)..(page+2)).to_a.select {|p| p > first_page && p < last_page}
end
pages = pages.compact.uniq.sort
if pages.size > 1
pages
else
[]
end
end
def items_per_page
ActiveSupport::Deprecation.warn "Paginator#items_per_page will be removed. Use #per_page instead."
per_page
end
def current
ActiveSupport::Deprecation.warn "Paginator#current will be removed. Use .offset instead of .current.offset."
self
end
end
# Paginates the given scope or model. Returns a Paginator instance and
# the collection of objects for the current page.
#
# Options:
# :parameter name of the page parameter
#
# Examples:
# @user_pages, @users = paginate User.where(:status => 1)
#
def paginate(scope, options={})
options = options.dup
paginator = paginator(scope.count, options)
collection = scope.limit(paginator.per_page).offset(paginator.offset).to_a
return paginator, collection
end
def paginator(item_count, options={})
options.assert_valid_keys :parameter, :per_page
page_param = options[:parameter] || :page
page = (params[page_param] || 1).to_i
per_page = options[:per_page] || per_page_option
Paginator.new(item_count, per_page, page, page_param)
end
module Helper
include Redmine::I18n
# Renders the pagination links for the given paginator.
#
# Options:
# :per_page_links if set to false, the "Per page" links are not rendered
#
def pagination_links_full(*args)
pagination_links_each(*args) do |text, parameters, options|
if block_given?
yield text, parameters, options
else
link_to text, {:params => request.query_parameters.merge(parameters)}, options
end
end
end
# Yields the given block with the text and parameters
# for each pagination link and returns a string that represents the links
def pagination_links_each(paginator, count=nil, options={}, &block)
options.assert_valid_keys :per_page_links
per_page_links = options.delete(:per_page_links)
per_page_links = false if count.nil?
page_param = paginator.page_param
html = +'<ul class="pages">'
if paginator.multiple_pages?
# \xc2\xab(utf-8) = «
text = "\xc2\xab " + l(:label_previous)
if paginator.previous_page
html << content_tag('li',
yield(text, {page_param => paginator.previous_page},
:accesskey => accesskey(:previous)),
:class => 'previous page')
else
html << content_tag('li', content_tag('span', text), :class => 'previous')
end
end
previous = nil
paginator.linked_pages.each do |page|
if previous && previous != page - 1
html << content_tag('li', content_tag('span', '…'.html_safe), :class => 'spacer')
end
if page == paginator.page
html << content_tag('li', content_tag('span', page.to_s), :class => 'current')
else
html << content_tag('li',
yield(page.to_s, {page_param => page}),
:class => 'page')
end
previous = page
end
if paginator.multiple_pages?
# \xc2\xbb(utf-8) = »
text = l(:label_next) + " \xc2\xbb"
if paginator.next_page
html << content_tag('li',
yield(text, {page_param => paginator.next_page},
:accesskey => accesskey(:next)),
:class => 'next page')
else
html << content_tag('li', content_tag('span', text), :class => 'next')
end
end
html << '</ul>'
info = ''.html_safe
info << content_tag('span', "(#{paginator.first_item}-#{paginator.last_item}/#{paginator.item_count})", :class => 'items') + ' '
if per_page_links != false && links = per_page_links(paginator, &block)
info << content_tag('span', links.to_s, :class => 'per-page')
end
html << content_tag('span', info)
html.html_safe
end
# Renders the "Per page" links.
def per_page_links(paginator, &block)
values = per_page_options(paginator.per_page, paginator.item_count)
if values.any?
links = values.collect do |n|
if n == paginator.per_page
content_tag('span', n.to_s, :class => 'selected')
else
yield(n, :per_page => n, paginator.page_param => nil)
end
end
l(:label_display_per_page, links.join(', ')).html_safe
end
end
def per_page_options(selected=nil, item_count=nil)
options = Setting.per_page_options_array
if item_count && options.any?
if item_count > options.first
max = options.detect {|value| value >= item_count} || item_count
else
max = item_count
end
options = options.select {|value| value <= max || value == selected}
end
if options.empty? || (options.size == 1 && options.first == selected)
[]
else
options
end
end
end
end
end
|