objectreload-pagination 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +3 -0
- data/LICENSE +21 -0
- data/README.rdoc +35 -0
- data/Rakefile +55 -0
- data/init.rb +1 -0
- data/lib/active_record/base_extensions.rb +19 -0
- data/lib/active_record/scope_extensions.rb +6 -0
- data/lib/pagination.rb +12 -0
- data/lib/pagination/collection.rb +62 -0
- data/lib/pagination/enumerable.rb +5 -0
- data/lib/pagination/named_scope.rb +5 -0
- data/lib/pagination/version.rb +9 -0
- data/lib/pagination/view_helpers.rb +322 -0
- data/test/active_record_extentions_test.rb +48 -0
- data/test/collection_test.rb +71 -0
- data/test/lib/view_test_process.rb +180 -0
- data/test/test_helper.rb +36 -0
- data/test/view_helpers_test.rb +224 -0
- metadata +77 -0
data/CHANGELOG.rdoc
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2009 Mateusz Drożdżyński
|
2
|
+
Based partially on will_paginate (c) 2007 PJ Hyett and Mislav Marohnić
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
Display options:
|
2
|
+
:previous_label -- default: "« Previous" (this parameter is called :prev_label in versions 2.3.2 and older!)
|
3
|
+
:next_label -- default: "Next »"
|
4
|
+
:page_links -- when false, only previous/next links are rendered (default: true)
|
5
|
+
:inner_window -- how many links are shown around the current page (default: 4)
|
6
|
+
:outer_window -- how many links are around the first and the last page (default: 1)
|
7
|
+
:separator -- string separator for page HTML elements (default: single space)
|
8
|
+
:controls -- display controls only at the :top or :bottom of the pagination block (default: :both)
|
9
|
+
:per_page -- number of items displayed per page (default: 10)
|
10
|
+
|
11
|
+
HTML options:
|
12
|
+
:class -- CSS class name for the generated DIV (default: "pagination")
|
13
|
+
:container -- toggles rendering of the DIV container for pagination links, set to false only when you are rendering your own pagination markup (default: true)
|
14
|
+
:id -- HTML ID for the container (default: nil). Pass +true+ to have the ID automatically generated from the class name of objects in collection: for example, paginating
|
15
|
+
ArticleComment models would yield an ID of "article_comments_pagination".
|
16
|
+
|
17
|
+
Advanced options:
|
18
|
+
:param_name -- parameter name for page number in URLs (default: :page)
|
19
|
+
:params -- additional parameters when generating pagination links (eg. :controller => "foo", :action => nil)
|
20
|
+
:renderer -- class name, class or instance of a link renderer (default: Pagination::LinkRenderer)
|
21
|
+
|
22
|
+
|
23
|
+
All options not recognized by paginate will become HTML attributes on the container
|
24
|
+
element for pagination links (the DIV).
|
25
|
+
For example:
|
26
|
+
|
27
|
+
<% paginate @posts, :style => 'font-size: small' do |posts| %>
|
28
|
+
...
|
29
|
+
<% end %>
|
30
|
+
|
31
|
+
... will result in:
|
32
|
+
|
33
|
+
<div class="pagination" style="font-size: small"> ... </div>
|
34
|
+
|
35
|
+
No changes in controllers.
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "objectreload-pagination"
|
8
|
+
gem.summary = "Simple pagination - without changes in controllers"
|
9
|
+
gem.email = "gems@objectreload.com"
|
10
|
+
gem.homepage = "http://github.com/objectreload/pagination"
|
11
|
+
gem.authors = ["Mateusz Drozdzynski"]
|
12
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
13
|
+
end
|
14
|
+
Jeweler::GemcutterTasks.new
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'rake/testtask'
|
20
|
+
Rake::TestTask.new(:test) do |test|
|
21
|
+
test.libs << 'lib' << 'test'
|
22
|
+
test.pattern = 'test/**/*_test.rb'
|
23
|
+
test.verbose = true
|
24
|
+
end
|
25
|
+
|
26
|
+
begin
|
27
|
+
require 'rcov/rcovtask'
|
28
|
+
Rcov::RcovTask.new do |test|
|
29
|
+
test.libs << 'test'
|
30
|
+
test.pattern = 'test/**/*_test.rb'
|
31
|
+
test.verbose = true
|
32
|
+
end
|
33
|
+
rescue LoadError
|
34
|
+
task :rcov do
|
35
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
task :test => :check_dependencies
|
40
|
+
|
41
|
+
task :default => :test
|
42
|
+
|
43
|
+
require 'rake/rdoctask'
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
if File.exist?('VERSION')
|
46
|
+
version = File.read('VERSION')
|
47
|
+
else
|
48
|
+
version = ""
|
49
|
+
end
|
50
|
+
|
51
|
+
rdoc.rdoc_dir = 'rdoc'
|
52
|
+
rdoc.title = "pagination_gem #{version}"
|
53
|
+
rdoc.rdoc_files.include('README*')
|
54
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'pagination'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
ActiveRecord::Base.class_eval do
|
2
|
+
class << self
|
3
|
+
VALID_FIND_OPTIONS = VALID_FIND_OPTIONS + [:eager]
|
4
|
+
|
5
|
+
def find_every_with_scope(options)
|
6
|
+
if options.delete(:eager)
|
7
|
+
find_every_without_scope(options)
|
8
|
+
else
|
9
|
+
scoped(options)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
alias_method_chain :find_every, :scope
|
13
|
+
|
14
|
+
def find_initial_with_eager_loading(options)
|
15
|
+
find_initial_without_eager_loading(options.merge(:eager => true))
|
16
|
+
end
|
17
|
+
alias_method_chain :find_initial, :eager_loading
|
18
|
+
end
|
19
|
+
end
|
data/lib/pagination.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# Loads extensions to Ruby on Rails libraries needed to support pagination and lazy loading
|
2
|
+
require 'active_record/base_extensions'
|
3
|
+
require 'active_record/scope_extensions'
|
4
|
+
|
5
|
+
# Loads internal pagination classes
|
6
|
+
require 'pagination/collection'
|
7
|
+
require 'pagination/named_scope'
|
8
|
+
require 'pagination/enumerable'
|
9
|
+
require 'pagination/view_helpers'
|
10
|
+
|
11
|
+
# Loads the :paginate view helper
|
12
|
+
ActionView::Base.send :include, Pagination::ViewHelpers
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Pagination
|
2
|
+
class InvalidPage < ArgumentError
|
3
|
+
def initialize(page, max = 1)
|
4
|
+
super "#{page} must be greater than 0" if page < 1
|
5
|
+
super "#{page} must be less than #{max}" if page >= 1
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class Collection < Array
|
10
|
+
attr_reader :current_page, :per_page, :total_entries, :total_pages
|
11
|
+
|
12
|
+
def initialize(options = {})
|
13
|
+
@collection = options[:collection]
|
14
|
+
|
15
|
+
@current_page = options[:current_page].to_i
|
16
|
+
raise InvalidPage.new(@current_page) if @current_page < 1
|
17
|
+
|
18
|
+
@per_page = options[:per_page].to_i
|
19
|
+
raise ArgumentError, "`per_page` setting cannot be less than 1 (#{@per_page} given)" if @per_page < 1
|
20
|
+
|
21
|
+
self.replace(@collection.paginate(:limit => limit, :offset => offset))
|
22
|
+
|
23
|
+
self.total_entries ||= @collection.count
|
24
|
+
raise InvalidPage.new(current_page, total_pages) if current_page > total_pages
|
25
|
+
end
|
26
|
+
|
27
|
+
def previous_page
|
28
|
+
current_page - 1 if current_page > 1
|
29
|
+
end
|
30
|
+
|
31
|
+
def next_page
|
32
|
+
current_page + 1 if current_page < total_pages
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def limit
|
38
|
+
per_page
|
39
|
+
end
|
40
|
+
|
41
|
+
def offset
|
42
|
+
offset = (current_page-1)*limit
|
43
|
+
end
|
44
|
+
|
45
|
+
def total_entries=(number)
|
46
|
+
@total_entries = number.to_i
|
47
|
+
@total_pages = @total_entries > 0 ? (@total_entries / per_page.to_f).ceil : 1
|
48
|
+
end
|
49
|
+
|
50
|
+
def replace(array)
|
51
|
+
result = super
|
52
|
+
|
53
|
+
# The collection is shorter then page limit? Rejoice, because
|
54
|
+
# then we know that we are on the last page!
|
55
|
+
if total_entries.nil? and length < per_page and (current_page == 1 or length > 0)
|
56
|
+
self.total_entries = offset + length
|
57
|
+
end
|
58
|
+
|
59
|
+
result
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,322 @@
|
|
1
|
+
module Pagination
|
2
|
+
# = Pagination view helpers
|
3
|
+
#
|
4
|
+
# The main view helper, #paginate, renders
|
5
|
+
# pagination links around (top and bottom) given collection. The helper itself is lightweight
|
6
|
+
# and serves only as a wrapper around LinkRenderer instantiation; the
|
7
|
+
# renderer then does all the hard work of generating the HTML.
|
8
|
+
#
|
9
|
+
# == Global options for helpers
|
10
|
+
#
|
11
|
+
# Options for pagination helpers are optional and get their default values from the
|
12
|
+
# <tt>Pagination::ViewHelpers.pagination_options</tt> hash. You can write to this hash to
|
13
|
+
# override default options on the global level:
|
14
|
+
#
|
15
|
+
# Pagination::ViewHelpers.pagination_options[:previous_label] = 'Previous page'
|
16
|
+
#
|
17
|
+
# By putting this into "config/initializers/pagination.rb" (or simply environment.rb in
|
18
|
+
# older versions of Rails) you can easily translate link texts to previous
|
19
|
+
# and next pages, as well as override some other defaults to your liking.
|
20
|
+
module ViewHelpers
|
21
|
+
# default options that can be overridden on the global level
|
22
|
+
@@pagination_options = {
|
23
|
+
:class => 'pagination',
|
24
|
+
:previous_label => '« Previous',
|
25
|
+
:next_label => 'Next »',
|
26
|
+
:inner_window => 4, # links around the current page
|
27
|
+
:outer_window => 1, # links around beginning and end
|
28
|
+
:separator => ' ', # single space is friendly to spiders and non-graphic browsers
|
29
|
+
:controls => :both,
|
30
|
+
:per_page => 10,
|
31
|
+
:param_name => :page,
|
32
|
+
:params => nil,
|
33
|
+
:renderer => 'Pagination::LinkRenderer',
|
34
|
+
:page_links => true,
|
35
|
+
:container => true
|
36
|
+
}
|
37
|
+
mattr_reader :pagination_options
|
38
|
+
|
39
|
+
# Renders Digg/Flickr-style pagination for a Pagination::Collection
|
40
|
+
# object. Nil is returned if there is only one page in total; no point in
|
41
|
+
# rendering the pagination in that case...
|
42
|
+
#
|
43
|
+
# ==== Options
|
44
|
+
# Display options:
|
45
|
+
# * <tt>:previous_label</tt> -- default: "« Previous" (this parameter is called <tt>:prev_label</tt> in versions <b>2.3.2</b> and older!)
|
46
|
+
# * <tt>:next_label</tt> -- default: "Next »"
|
47
|
+
# * <tt>:page_links</tt> -- when false, only previous/next links are rendered (default: true)
|
48
|
+
# * <tt>:inner_window</tt> -- how many links are shown around the current page (default: 4)
|
49
|
+
# * <tt>:outer_window</tt> -- how many links are around the first and the last page (default: 1)
|
50
|
+
# * <tt>:separator</tt> -- string separator for page HTML elements (default: single space)
|
51
|
+
# * <tt>:controls</tt> -- display controls only at the <tt>:top</tt> or <tt>:bottom</tt> of the pagination block (default: <tt>:both</tt>)
|
52
|
+
# * <tt>:per_page</tt> -- number of items displayed per page (default: 10)
|
53
|
+
#
|
54
|
+
# HTML options:
|
55
|
+
# * <tt>:class</tt> -- CSS class name for the generated DIV (default: "pagination")
|
56
|
+
# * <tt>:container</tt> -- toggles rendering of the DIV container for pagination links, set to
|
57
|
+
# false only when you are rendering your own pagination markup (default: true)
|
58
|
+
# * <tt>:id</tt> -- HTML ID for the container (default: nil). Pass +true+ to have the ID
|
59
|
+
# automatically generated from the class name of objects in collection: for example, paginating
|
60
|
+
# ArticleComment models would yield an ID of "article_comments_pagination".
|
61
|
+
#
|
62
|
+
# Advanced options:
|
63
|
+
# * <tt>:param_name</tt> -- parameter name for page number in URLs (default: <tt>:page</tt>)
|
64
|
+
# * <tt>:params</tt> -- additional parameters when generating pagination links
|
65
|
+
# (eg. <tt>:controller => "foo", :action => nil</tt>)
|
66
|
+
# * <tt>:renderer</tt> -- class name, class or instance of a link renderer (default:
|
67
|
+
# <tt>Pagination::LinkRenderer</tt>)
|
68
|
+
#
|
69
|
+
# All options not recognized by paginate will become HTML attributes on the container
|
70
|
+
# element for pagination links (the DIV). For example:
|
71
|
+
#
|
72
|
+
# <% paginate @posts, :style => 'font-size: small' do |posts| %>
|
73
|
+
# ...
|
74
|
+
# <% end %>
|
75
|
+
#
|
76
|
+
# ... will result in:
|
77
|
+
#
|
78
|
+
# <div class="pagination" style="font-size: small"> ... </div>
|
79
|
+
#
|
80
|
+
def paginate(collection = [], options = {}, &block)
|
81
|
+
options = options.symbolize_keys.reverse_merge Pagination::ViewHelpers.pagination_options
|
82
|
+
|
83
|
+
collection = Pagination::Collection.new(options.merge(:collection => collection, :current_page => params[options[:param_name]]|| 1))
|
84
|
+
yield collection and return nil unless collection.total_pages > 1
|
85
|
+
|
86
|
+
# get the renderer instance
|
87
|
+
renderer = case options[:renderer]
|
88
|
+
when String
|
89
|
+
options[:renderer].to_s.constantize.new
|
90
|
+
when Class
|
91
|
+
options[:renderer].new
|
92
|
+
else
|
93
|
+
options[:renderer]
|
94
|
+
end
|
95
|
+
|
96
|
+
# render HTML for pagination
|
97
|
+
renderer.prepare collection, options, self
|
98
|
+
pagination = renderer.to_html.to_s
|
99
|
+
|
100
|
+
if block_given?
|
101
|
+
top = [:top, :both].include?(options[:controls]) ? pagination : ""
|
102
|
+
bottom = [:bottom, :both].include?(options[:controls]) ? pagination : ""
|
103
|
+
unless ActionView::Base.respond_to? :erb_variable
|
104
|
+
concat top
|
105
|
+
yield collection
|
106
|
+
unless bottom.empty?
|
107
|
+
concat bottom
|
108
|
+
end
|
109
|
+
else
|
110
|
+
content = top + capture(&block) + bottom
|
111
|
+
concat(content, block.binding)
|
112
|
+
end
|
113
|
+
else
|
114
|
+
collection
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# This class does the heavy lifting of actually building the pagination
|
120
|
+
# links. It is used by the <tt>paginate</tt> helper internally.
|
121
|
+
class LinkRenderer
|
122
|
+
|
123
|
+
# The gap in page links is represented by:
|
124
|
+
#
|
125
|
+
# <span class="gap">…</span>
|
126
|
+
attr_accessor :gap_marker
|
127
|
+
|
128
|
+
def initialize
|
129
|
+
@gap_marker = '<span class="gap">…</span>'
|
130
|
+
end
|
131
|
+
|
132
|
+
# * +collection+ is a Pagination::Collection instance or any other object
|
133
|
+
# that conforms to that API
|
134
|
+
# * +options+ are forwarded from +paginate+ view helper
|
135
|
+
# * +template+ is the reference to the template being rendered
|
136
|
+
def prepare(collection, options, template)
|
137
|
+
@collection = collection
|
138
|
+
@options = options
|
139
|
+
@template = template
|
140
|
+
|
141
|
+
# reset values in case we're re-using this instance
|
142
|
+
@total_pages = @param_name = @url_string = nil
|
143
|
+
end
|
144
|
+
|
145
|
+
# Process it! This method returns the complete HTML string which contains
|
146
|
+
# pagination links. Feel free to subclass LinkRenderer and change this
|
147
|
+
# method as you see fit.
|
148
|
+
def to_html
|
149
|
+
links = @options[:page_links] ? windowed_links : []
|
150
|
+
# previous/next buttons
|
151
|
+
links.unshift page_link_or_span(@collection.previous_page, 'disabled prev_page', @options[:previous_label])
|
152
|
+
links.push page_link_or_span(@collection.next_page, 'disabled next_page', @options[:next_label])
|
153
|
+
|
154
|
+
html = links.join(@options[:separator])
|
155
|
+
@options[:container] ? @template.content_tag(:div, html, html_attributes) : html
|
156
|
+
end
|
157
|
+
|
158
|
+
# Returns the subset of +options+ this instance was initialized with that
|
159
|
+
# represent HTML attributes for the container element of pagination links.
|
160
|
+
def html_attributes
|
161
|
+
return @html_attributes if @html_attributes
|
162
|
+
@html_attributes = @options.except *(Pagination::ViewHelpers.pagination_options.keys - [:class])
|
163
|
+
# pagination of Post models will have the ID of "posts_pagination"
|
164
|
+
if @options[:container] and @options[:id] === true
|
165
|
+
@html_attributes[:id] = @collection.first.class.name.underscore.pluralize + '_pagination'
|
166
|
+
end
|
167
|
+
@html_attributes
|
168
|
+
end
|
169
|
+
|
170
|
+
protected
|
171
|
+
|
172
|
+
# Collects link items for visible page numbers.
|
173
|
+
def windowed_links
|
174
|
+
prev = nil
|
175
|
+
|
176
|
+
visible_page_numbers.inject [] do |links, n|
|
177
|
+
# detect gaps:
|
178
|
+
links << gap_marker if prev and n > prev + 1
|
179
|
+
links << page_link_or_span(n, 'current')
|
180
|
+
prev = n
|
181
|
+
links
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Calculates visible page numbers using the <tt>:inner_window</tt> and
|
186
|
+
# <tt>:outer_window</tt> options.
|
187
|
+
def visible_page_numbers
|
188
|
+
inner_window, outer_window = @options[:inner_window].to_i, @options[:outer_window].to_i
|
189
|
+
window_from = current_page - inner_window
|
190
|
+
window_to = current_page + inner_window
|
191
|
+
|
192
|
+
# adjust lower or upper limit if other is out of bounds
|
193
|
+
if window_to > total_pages
|
194
|
+
window_from -= window_to - total_pages
|
195
|
+
window_to = total_pages
|
196
|
+
end
|
197
|
+
if window_from < 1
|
198
|
+
window_to += 1 - window_from
|
199
|
+
window_from = 1
|
200
|
+
window_to = total_pages if window_to > total_pages
|
201
|
+
end
|
202
|
+
|
203
|
+
visible = (1..total_pages).to_a
|
204
|
+
left_gap = (2 + outer_window)...window_from
|
205
|
+
right_gap = (window_to + 1)...(total_pages - outer_window)
|
206
|
+
visible -= left_gap.to_a if left_gap.last - left_gap.first > 1
|
207
|
+
visible -= right_gap.to_a if right_gap.last - right_gap.first > 1
|
208
|
+
|
209
|
+
visible
|
210
|
+
end
|
211
|
+
|
212
|
+
def page_link_or_span(page, span_class, text = nil)
|
213
|
+
text ||= page.to_s
|
214
|
+
|
215
|
+
if page and page != current_page
|
216
|
+
classnames = span_class && span_class.index(' ') && span_class.split(' ', 2).last
|
217
|
+
page_link page, text, :rel => rel_value(page), :class => classnames
|
218
|
+
else
|
219
|
+
page_span page, text, :class => span_class
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def page_link(page, text, attributes = {})
|
224
|
+
@template.link_to text, url_for(page), attributes
|
225
|
+
end
|
226
|
+
|
227
|
+
def page_span(page, text, attributes = {})
|
228
|
+
@template.content_tag :span, text, attributes
|
229
|
+
end
|
230
|
+
|
231
|
+
# Returns URL params for +page_link_or_span+, taking the current GET params
|
232
|
+
# and <tt>:params</tt> option into account.
|
233
|
+
def url_for(page)
|
234
|
+
page_one = page == 1
|
235
|
+
unless @url_string and !page_one
|
236
|
+
@url_params = {}
|
237
|
+
# page links should preserve GET parameters
|
238
|
+
stringified_merge @url_params, @template.params if @template.request.get?
|
239
|
+
stringified_merge @url_params, @options[:params] if @options[:params]
|
240
|
+
|
241
|
+
if complex = param_name.index(/[^\w-]/)
|
242
|
+
page_param = parse_query_parameters("#{param_name}=#{page}")
|
243
|
+
|
244
|
+
stringified_merge @url_params, page_param
|
245
|
+
else
|
246
|
+
@url_params[param_name] = page_one ? 1 : 2
|
247
|
+
end
|
248
|
+
|
249
|
+
url = @template.url_for(@url_params)
|
250
|
+
return url if page_one
|
251
|
+
|
252
|
+
if complex
|
253
|
+
@url_string = url.sub(%r!((?:\?|&)#{CGI.escape param_name}=)#{page}!, "\\1\0")
|
254
|
+
return url
|
255
|
+
else
|
256
|
+
@url_string = url
|
257
|
+
@url_params[param_name] = 3
|
258
|
+
@template.url_for(@url_params).split(//).each_with_index do |char, i|
|
259
|
+
if char == '3' and url[i, 1] == '2'
|
260
|
+
@url_string[i] = "\0"
|
261
|
+
break
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
# finally!
|
267
|
+
@url_string.sub "\0", page.to_s
|
268
|
+
end
|
269
|
+
|
270
|
+
private
|
271
|
+
|
272
|
+
def rel_value(page)
|
273
|
+
case page
|
274
|
+
when @collection.previous_page; 'prev' + (page == 1 ? ' start' : '')
|
275
|
+
when @collection.next_page; 'next'
|
276
|
+
when 1; 'start'
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def current_page
|
281
|
+
@current_page ||= @collection.current_page
|
282
|
+
end
|
283
|
+
|
284
|
+
def total_pages
|
285
|
+
@total_pages ||= @collection.total_pages
|
286
|
+
end
|
287
|
+
|
288
|
+
def param_name
|
289
|
+
@param_name ||= @options[:param_name].to_s
|
290
|
+
end
|
291
|
+
|
292
|
+
# Recursively merge into target hash by using stringified keys from the other one
|
293
|
+
def stringified_merge(target, other)
|
294
|
+
other.each do |key, value|
|
295
|
+
key = key.to_s # this line is what it's all about!
|
296
|
+
existing = target[key]
|
297
|
+
|
298
|
+
if value.is_a?(Hash) and (existing.is_a?(Hash) or existing.nil?)
|
299
|
+
stringified_merge(existing || (target[key] = {}), value)
|
300
|
+
else
|
301
|
+
target[key] = value
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def parse_query_parameters(params)
|
307
|
+
if defined? Rack::Utils
|
308
|
+
# For Rails > 2.3
|
309
|
+
Rack::Utils.parse_nested_query(params)
|
310
|
+
elsif defined?(ActionController::AbstractRequest)
|
311
|
+
ActionController::AbstractRequest.parse_query_parameters(params)
|
312
|
+
elsif defined?(ActionController::UrlEncodedPairParser)
|
313
|
+
# For Rails > 2.2
|
314
|
+
ActionController::UrlEncodedPairParser.parse_query_parameters(params)
|
315
|
+
elsif defined?(CGIMethods)
|
316
|
+
CGIMethods.parse_query_parameters(params)
|
317
|
+
else
|
318
|
+
raise "unsupported ActionPack version"
|
319
|
+
end
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
require 'active_record/base_extensions'
|
3
|
+
require 'active_record/scope_extensions'
|
4
|
+
require 'mocha'
|
5
|
+
|
6
|
+
|
7
|
+
class ActiveRecordExtentionsTest < Test::Unit::TestCase
|
8
|
+
context "active record extentions" do
|
9
|
+
setup do
|
10
|
+
User.delete_all
|
11
|
+
Article.delete_all
|
12
|
+
|
13
|
+
@user1 = User.create :first_name => 'Bob', :last_name => 'Builder'
|
14
|
+
@user2 = User.create :first_name => 'Bob', :last_name => 'Builder2'
|
15
|
+
@user3 = User.create :first_name => 'Tom', :last_name => 'Builder'
|
16
|
+
|
17
|
+
5.times do |i|
|
18
|
+
Article.create(:title => "title_#{i}", :user => @user1)
|
19
|
+
end
|
20
|
+
|
21
|
+
3.times do |i|
|
22
|
+
Article.create!(:title => "2title_#{i}", :user => @user2)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
should "difference between Article.find_every_with_scope and Article.find_every_without_scope" do
|
27
|
+
users1 = User.all
|
28
|
+
users2 = User.all(:eager => true)
|
29
|
+
assert_equal users1, users2
|
30
|
+
assert_not_equal users1.class, users2.class
|
31
|
+
|
32
|
+
users1 = User.all(:conditions => {:first_name => 'Bob'})
|
33
|
+
users2 = User.all(:eager => true, :conditions => {:first_name => 'Bob'})
|
34
|
+
assert_equal users1, users2
|
35
|
+
assert_not_equal users1.class, users2.class
|
36
|
+
end
|
37
|
+
|
38
|
+
should "return ActiveRecord::NamedScope::Scope" do
|
39
|
+
assert_equal ActiveRecord::NamedScope::Scope, User.all.class
|
40
|
+
assert_equal ActiveRecord::NamedScope::Scope, User.all(:conditions => {:first_name => 'Bob'}).class
|
41
|
+
end
|
42
|
+
|
43
|
+
should "return an Array when called with :eager => true" do
|
44
|
+
assert_equal Array, Article.all(:eager => true).class
|
45
|
+
assert_equal Array, Article.all(:eager => true, :conditions => {:title => "title_1"}).class
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/pagination/collection'
|
3
|
+
require File.dirname(__FILE__) + '/../lib/pagination/enumerable'
|
4
|
+
|
5
|
+
class CollectionTest < Test::Unit::TestCase
|
6
|
+
context "collection test" do
|
7
|
+
setup do
|
8
|
+
@collection = ('a'..'e').to_a
|
9
|
+
end
|
10
|
+
|
11
|
+
should "return elements from specific range" do
|
12
|
+
# see: enumerable.rb
|
13
|
+
# limit = per_page
|
14
|
+
# offset = (current_page - 1) * limit
|
15
|
+
[
|
16
|
+
{ :offset => 0, :limit => 3, :expected => %w( a b c ) },
|
17
|
+
{ :offset => 3, :limit => 3, :expected => %w( d e ) },
|
18
|
+
{ :offset => 0, :limit => 5, :expected => %w( a b c d e ) },
|
19
|
+
{ :offset => 6, :limit => 3, :expected => [] },
|
20
|
+
].
|
21
|
+
each do |conditions|
|
22
|
+
expected = conditions.delete :expected
|
23
|
+
assert_equal expected, @collection.paginate(conditions)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "init pagination collection" do
|
28
|
+
setup do
|
29
|
+
@collection = [1,2,3,4,5]
|
30
|
+
@paginated_collection = paginate_collection(@collection)
|
31
|
+
end
|
32
|
+
|
33
|
+
should "return total pages" do
|
34
|
+
assert_equal 3, @paginated_collection.total_pages
|
35
|
+
end
|
36
|
+
|
37
|
+
should "return previous page" do
|
38
|
+
assert_equal 1, @paginated_collection.previous_page
|
39
|
+
end
|
40
|
+
|
41
|
+
should "return next page" do
|
42
|
+
assert_equal 3, @paginated_collection.next_page
|
43
|
+
end
|
44
|
+
|
45
|
+
should "array be shorter after paginate" do
|
46
|
+
pag_array = paginate_collection(@collection, 1, 4)
|
47
|
+
assert_not_equal @collection, pag_array.count
|
48
|
+
assert_equal 4, pag_array.count
|
49
|
+
end
|
50
|
+
|
51
|
+
should "rise an error InvalidPage" do
|
52
|
+
assert_raise(Pagination::InvalidPage) { paginate_collection(@collection, -2, 2) }
|
53
|
+
assert_raise(Pagination::InvalidPage) { paginate_collection(@collection, 1000, 2) }
|
54
|
+
end
|
55
|
+
|
56
|
+
should "rise an error ArgumentError" do
|
57
|
+
assert_raise(ArgumentError) { paginate_collection(@collection, 2, -2) }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
def paginate_collection(collection, current_page=2, per_page=2, total_entries=nil)
|
64
|
+
Pagination::Collection.new(
|
65
|
+
:collection => collection,
|
66
|
+
:current_page => current_page,
|
67
|
+
:per_page => per_page,
|
68
|
+
:total_entries => total_entries
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'action_controller'
|
2
|
+
require 'action_controller/test_process'
|
3
|
+
|
4
|
+
require 'pagination'
|
5
|
+
|
6
|
+
ActionController::Routing::Routes.draw do |map|
|
7
|
+
map.connect 'dummy/page/:page', :controller => 'dummy'
|
8
|
+
map.connect 'dummy/dots/page.:page', :controller => 'dummy', :action => 'dots'
|
9
|
+
map.connect 'ibocorp/:page', :controller => 'ibocorp',
|
10
|
+
:requirements => { :page => /\d+/ },
|
11
|
+
:defaults => { :page => 1 }
|
12
|
+
|
13
|
+
map.connect ':controller/:action/:id'
|
14
|
+
end
|
15
|
+
|
16
|
+
ActionController::Base.perform_caching = false
|
17
|
+
|
18
|
+
class Pagination::ViewTestCase < Test::Unit::TestCase
|
19
|
+
if defined?(ActionController::TestCase::Assertions)
|
20
|
+
include ActionController::TestCase::Assertions
|
21
|
+
end
|
22
|
+
if defined?(ActiveSupport::Testing::Deprecation)
|
23
|
+
include ActiveSupport::Testing::Deprecation
|
24
|
+
end
|
25
|
+
|
26
|
+
def setup
|
27
|
+
super
|
28
|
+
@controller = DummyController.new
|
29
|
+
@request = @controller.request
|
30
|
+
@html_result = nil
|
31
|
+
@template = '<%= paginate collection, options do |tmp|; tmp.each do |t|; end; end %>'
|
32
|
+
|
33
|
+
@view = ActionView::Base.new
|
34
|
+
@view.assigns['controller'] = @controller
|
35
|
+
@view.assigns['_request'] = @request
|
36
|
+
@view.assigns['_params'] = @request.params
|
37
|
+
end
|
38
|
+
|
39
|
+
def default_test; end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def paginate(collection = {}, options = {}, &block)
|
44
|
+
|
45
|
+
if collection.instance_of? Hash
|
46
|
+
@request.params :page => collection[:page] || 1
|
47
|
+
collection = [1,2,3,4,5,6,7,8,9,10,11]
|
48
|
+
end
|
49
|
+
options = {:per_page => 4, :controls => :top}.merge(options)
|
50
|
+
|
51
|
+
locals = { :collection => collection, :options => options }
|
52
|
+
|
53
|
+
unless @view.respond_to? :render_template
|
54
|
+
# Rails 2.2
|
55
|
+
@html_result = ActionView::InlineTemplate.new(@template).render(@view, locals)
|
56
|
+
else
|
57
|
+
if defined? ActionView::InlineTemplate
|
58
|
+
# Rails 2.1
|
59
|
+
args = [ ActionView::InlineTemplate.new(@view, @template, locals) ]
|
60
|
+
else
|
61
|
+
# older Rails versions
|
62
|
+
args = [nil, @template, nil, locals]
|
63
|
+
end
|
64
|
+
|
65
|
+
@html_result = @view.render_template(*args)
|
66
|
+
end
|
67
|
+
|
68
|
+
@html_document = HTML::Document.new(@html_result, true, false)
|
69
|
+
|
70
|
+
if block_given?
|
71
|
+
classname = options[:class] || Pagination::ViewHelpers.pagination_options[:class]
|
72
|
+
assert_select("div.#{classname}",1 , 'no main DIV', &block)
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
def response_from_page_or_rjs
|
78
|
+
@html_document.root
|
79
|
+
end
|
80
|
+
|
81
|
+
def validate_page_numbers expected, links, param_name = :page
|
82
|
+
param_pattern = /\W#{CGI.escape(param_name.to_s)}=([^&]*)/
|
83
|
+
|
84
|
+
assert_equal(expected, links.map { |e|
|
85
|
+
e['href'] =~ param_pattern
|
86
|
+
$1 ? $1.to_i : $1
|
87
|
+
})
|
88
|
+
end
|
89
|
+
|
90
|
+
def assert_links_match pattern, links = nil, numbers = nil
|
91
|
+
links ||= assert_select 'div.pagination a[href]' do |elements|
|
92
|
+
elements
|
93
|
+
end
|
94
|
+
|
95
|
+
pages = [] if numbers
|
96
|
+
|
97
|
+
links.each do |el|
|
98
|
+
assert_match pattern, el['href']
|
99
|
+
if numbers
|
100
|
+
el['href'] =~ pattern
|
101
|
+
pages << ($1.nil?? nil : $1.to_i)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
assert_equal numbers, pages, "page numbers don't match" if numbers
|
106
|
+
end
|
107
|
+
|
108
|
+
def assert_no_links_match pattern
|
109
|
+
assert_select 'div.pagination a[href]' do |elements|
|
110
|
+
elements.each do |el|
|
111
|
+
assert_no_match pattern, el['href']
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
class DummyRequest
|
118
|
+
attr_accessor :symbolized_path_parameters
|
119
|
+
|
120
|
+
def initialize
|
121
|
+
@get = true
|
122
|
+
@params = {}
|
123
|
+
@symbolized_path_parameters = { :controller => 'foo', :action => 'bar'}
|
124
|
+
end
|
125
|
+
|
126
|
+
def get?
|
127
|
+
@get
|
128
|
+
end
|
129
|
+
|
130
|
+
def post
|
131
|
+
@get = false
|
132
|
+
end
|
133
|
+
|
134
|
+
def relative_url_root
|
135
|
+
''
|
136
|
+
end
|
137
|
+
|
138
|
+
def params(more = nil)
|
139
|
+
@params.update(more) if more
|
140
|
+
@params
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class DummyController
|
145
|
+
attr_reader :request
|
146
|
+
attr_accessor :controller_name
|
147
|
+
|
148
|
+
def initialize
|
149
|
+
@request = DummyRequest.new
|
150
|
+
@url = ActionController::UrlRewriter.new(@request, @request.params)
|
151
|
+
end
|
152
|
+
|
153
|
+
def params
|
154
|
+
@request.params
|
155
|
+
end
|
156
|
+
|
157
|
+
def url_for(params)
|
158
|
+
@url.rewrite(params)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
module HTML
|
163
|
+
Node.class_eval do
|
164
|
+
def inner_text
|
165
|
+
children.map(&:inner_text).join('')
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
Text.class_eval do
|
170
|
+
def inner_text
|
171
|
+
self.to_s
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
Tag.class_eval do
|
176
|
+
def inner_text
|
177
|
+
childless?? '' : super
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'activerecord'
|
3
|
+
require 'shoulda'
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
|
7
|
+
ActiveRecord::Base.configurations = {'sqlite3' => {:adapter => 'sqlite3', :database => ':memory:'}}
|
8
|
+
ActiveRecord::Base.establish_connection('sqlite3')
|
9
|
+
|
10
|
+
ActiveRecord::Base.logger = Logger.new(STDERR)
|
11
|
+
ActiveRecord::Base.logger.level = Logger::WARN
|
12
|
+
|
13
|
+
ActiveRecord::Schema.define(:version => 0) do
|
14
|
+
create_table :users do |t|
|
15
|
+
t.string :first_name, :default => ''
|
16
|
+
t.string :last_name, :default => ''
|
17
|
+
end
|
18
|
+
|
19
|
+
create_table :articles do |t|
|
20
|
+
t.string :title, :default => ''
|
21
|
+
t.integer :user_id
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class User < ActiveRecord::Base
|
26
|
+
has_many :articles
|
27
|
+
named_scope :bob, :conditions => {:first_name => 'Bob'}
|
28
|
+
|
29
|
+
def find_all
|
30
|
+
User.find_all
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Article < ActiveRecord::Base
|
35
|
+
belongs_to :user
|
36
|
+
end
|
@@ -0,0 +1,224 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
require File.dirname(__FILE__) + '/lib/view_test_process'
|
3
|
+
|
4
|
+
class ViewHelpersTest < Pagination::ViewTestCase
|
5
|
+
context "paginate method" do
|
6
|
+
|
7
|
+
should "return full output" do
|
8
|
+
paginate({:page => 1})
|
9
|
+
expected = <<-HTML
|
10
|
+
<div class="pagination"><span class="disabled prev_page">« Previous</span>
|
11
|
+
<span class="current">1</span>
|
12
|
+
<a href="/foo/bar?page=2" rel="next">2</a>
|
13
|
+
<a href="/foo/bar?page=3">3</a>
|
14
|
+
<a href="/foo/bar?page=2" class="next_page" rel="next">Next »</a></div>
|
15
|
+
HTML
|
16
|
+
expected.strip!.gsub!(/\s{2,}/, ' ')
|
17
|
+
|
18
|
+
assert_dom_equal expected, @html_result
|
19
|
+
end
|
20
|
+
|
21
|
+
should "show links to pages" do
|
22
|
+
paginate do |pagination|
|
23
|
+
assert_select 'a[href]', 3 do |elements|
|
24
|
+
validate_page_numbers [2,3,2], elements
|
25
|
+
assert_select elements.last, ':last-child', "Next »"
|
26
|
+
end
|
27
|
+
assert_select 'span', 2
|
28
|
+
assert_select 'span.disabled:first-child', '« Previous'
|
29
|
+
assert_select 'span.current', '1'
|
30
|
+
assert_equal '« Previous 1 2 3 Next »', pagination.first.inner_text
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
should "paginate with options" do
|
35
|
+
paginate({:page => 2},
|
36
|
+
:class => 'paginate', :previous_label => 'Prev', :next_label => 'Next') do
|
37
|
+
assert_select 'a[href]', 4 do |elements|
|
38
|
+
validate_page_numbers [1,1,3,3], elements
|
39
|
+
# test rel attribute values:
|
40
|
+
assert_select elements[1], 'a', '1' do |link|
|
41
|
+
assert_equal 'prev start', link.first['rel']
|
42
|
+
end
|
43
|
+
assert_select elements.first, 'a', "Prev" do |link|
|
44
|
+
assert_equal 'prev start', link.first['rel']
|
45
|
+
end
|
46
|
+
assert_select elements.last, 'a', "Next" do |link|
|
47
|
+
assert_equal 'next', link.first['rel']
|
48
|
+
end
|
49
|
+
end
|
50
|
+
assert_select 'span.current', '2'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
should "paginate using renderer class" do
|
55
|
+
paginate( {}, :per_page => 5, :renderer => AdditionalLinkAttributesRenderer) do
|
56
|
+
assert_select 'a[default=true]', 3
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
should "no pagination when page count is one" do
|
61
|
+
paginate({:page => 1}, {:per_page => 30})
|
62
|
+
assert_equal '', @html_result
|
63
|
+
end
|
64
|
+
|
65
|
+
should "paginate using renderer instance" do
|
66
|
+
renderer = Pagination::LinkRenderer.new
|
67
|
+
renderer.gap_marker = '<span class="my-gap">~~</span>'
|
68
|
+
|
69
|
+
paginate({}, {:per_page => 2, :inner_window => 0, :outer_window => 0, :renderer => renderer}) do
|
70
|
+
assert_select 'span.my-gap', '~~'
|
71
|
+
end
|
72
|
+
|
73
|
+
renderer = AdditionalLinkAttributesRenderer.new(:title => 'rendered')
|
74
|
+
paginate({}, :per_page => 5, :renderer => renderer) do
|
75
|
+
assert_select 'a[title=rendered]', 3
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
should "previous next links have classnames" do
|
80
|
+
paginate do |pagination|
|
81
|
+
assert_select 'span.disabled.prev_page:first-child'
|
82
|
+
assert_select 'a.next_page[href]:last-child'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
should "paginate without container" do
|
87
|
+
paginate({}, :container => false)
|
88
|
+
assert_select 'div.pagination', 0, 'main DIV present when it shouldn\'t'
|
89
|
+
end
|
90
|
+
|
91
|
+
should "paginate without page links" do
|
92
|
+
paginate({:page => 2}, :page_links => false) do
|
93
|
+
assert_select 'a[href]', 2 do |elements|
|
94
|
+
validate_page_numbers [1,3], elements
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
should "paginate windows" do
|
100
|
+
paginate({:page => 6}, {:per_page => 1, :inner_window => 1}) do |pagination|
|
101
|
+
assert_select 'a[href]', 8 do |elements|
|
102
|
+
validate_page_numbers [5,1,2,5,7,10,11,7], elements
|
103
|
+
assert_select elements.first, 'a', '« Previous'
|
104
|
+
assert_select elements.last, 'a', 'Next »'
|
105
|
+
end
|
106
|
+
assert_select 'span.current', '6'
|
107
|
+
assert_equal '« Previous 1 2 … 5 6 7 … 10 11 Next »', pagination.first.inner_text
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
should "paginate eliminates small gaps" do
|
112
|
+
paginate({:page => 6}, {:per_page => 1, :inner_window => 2}) do
|
113
|
+
assert_select 'a[href]', 12 do |elements|
|
114
|
+
validate_page_numbers [5,1,2,3,4,5,7,8,9,10,11,7], elements
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
should "return container id" do
|
120
|
+
paginate do |div|
|
121
|
+
assert_nil div.first['id']
|
122
|
+
end
|
123
|
+
|
124
|
+
# magic ID
|
125
|
+
paginate({}, :id => true) do |div|
|
126
|
+
assert_equal 'fixnums_pagination', div.first['id']
|
127
|
+
end
|
128
|
+
|
129
|
+
# explicit ID
|
130
|
+
paginate({}, :id => 'custom_id') do |div|
|
131
|
+
assert_equal 'custom_id', div.first['id']
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
should "paginate with custom page param" do
|
136
|
+
paginate({}, {:param_name => :developers_page}) do
|
137
|
+
assert_select 'a[href]', 3 do |elements|
|
138
|
+
validate_page_numbers [2,3,2], elements, :developers_page
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
should "paginate preserves parameters on get" do
|
144
|
+
@request.params :foo => { :bar => 'baz' }
|
145
|
+
paginate
|
146
|
+
assert_links_match /foo%5Bbar%5D=baz/
|
147
|
+
end
|
148
|
+
|
149
|
+
should "paginate doesnt preserve parameters on post" do
|
150
|
+
@request.post
|
151
|
+
@request.params :foo => 'bar'
|
152
|
+
paginate
|
153
|
+
assert_no_links_match /foo=bar/
|
154
|
+
end
|
155
|
+
|
156
|
+
should "adding additional parameters" do
|
157
|
+
paginate({}, :params => { :foo => 'bar' })
|
158
|
+
assert_links_match /foo=bar/
|
159
|
+
end
|
160
|
+
|
161
|
+
should "adding anchor parameter" do
|
162
|
+
paginate({}, :params => { :anchor => 'anchor' })
|
163
|
+
assert_links_match /#anchor$/
|
164
|
+
end
|
165
|
+
|
166
|
+
should "removing arbitrary parameters" do
|
167
|
+
@request.params :foo => 'bar'
|
168
|
+
paginate({}, :params => { :foo => nil })
|
169
|
+
assert_no_links_match /foo=bar/
|
170
|
+
end
|
171
|
+
|
172
|
+
should "adding additional route parameters" do
|
173
|
+
paginate({}, :params => { :controller => 'baz', :action => 'list' })
|
174
|
+
assert_links_match %r{\Wbaz/list\W}
|
175
|
+
end
|
176
|
+
|
177
|
+
should "will paginate with atmark url" do
|
178
|
+
@request.symbolized_path_parameters[:action] = "@tag"
|
179
|
+
renderer = Pagination::LinkRenderer.new
|
180
|
+
|
181
|
+
paginate({ :page => 1 }, :renderer=>renderer)
|
182
|
+
assert_links_match %r[/foo/@tag\?page=\d]
|
183
|
+
end
|
184
|
+
|
185
|
+
should "custom routing page param" do
|
186
|
+
@request.symbolized_path_parameters.update :controller => 'dummy', :action => nil
|
187
|
+
paginate({}, :per_page => 2) do
|
188
|
+
assert_select 'a[href]', 6 do |links|
|
189
|
+
assert_links_match %r{/page/(\d+)$}, links, [2, 3, 4, 5, 6, 2]
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
should "custom routing page param with dot separator" do
|
195
|
+
@request.symbolized_path_parameters.update :controller => 'dummy', :action => 'dots'
|
196
|
+
paginate({}, :per_page => 2) do
|
197
|
+
assert_select 'a[href]', 6 do |links|
|
198
|
+
assert_links_match %r{/page\.(\d+)$}, links, [2, 3, 4, 5, 6, 2]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
should "custom routing with first page hidden" do
|
204
|
+
@request.symbolized_path_parameters.update :controller => 'ibocorp', :action => nil
|
205
|
+
paginate({:page => 2}, :per_page => 2) do
|
206
|
+
assert_select 'a[href]', 7 do |links|
|
207
|
+
assert_links_match %r{/ibocorp(?:/(\d+))?$}, links, [nil, nil, 3, 4, 5, 6, 3]
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
class AdditionalLinkAttributesRenderer < Pagination::LinkRenderer
|
216
|
+
def initialize(link_attributes = nil)
|
217
|
+
super()
|
218
|
+
@additional_link_attributes = link_attributes || { :default => 'true' }
|
219
|
+
end
|
220
|
+
|
221
|
+
def page_link(page, text, attributes = {})
|
222
|
+
@template.link_to text, url_for(page), attributes.merge(@additional_link_attributes)
|
223
|
+
end
|
224
|
+
end
|
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: objectreload-pagination
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mateusz Drozdzynski
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-13 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: gems@objectreload.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README.rdoc
|
25
|
+
files:
|
26
|
+
- CHANGELOG.rdoc
|
27
|
+
- LICENSE
|
28
|
+
- README.rdoc
|
29
|
+
- Rakefile
|
30
|
+
- init.rb
|
31
|
+
- lib/active_record/base_extensions.rb
|
32
|
+
- lib/active_record/scope_extensions.rb
|
33
|
+
- lib/pagination.rb
|
34
|
+
- lib/pagination/collection.rb
|
35
|
+
- lib/pagination/enumerable.rb
|
36
|
+
- lib/pagination/named_scope.rb
|
37
|
+
- lib/pagination/version.rb
|
38
|
+
- lib/pagination/view_helpers.rb
|
39
|
+
- test/active_record_extentions_test.rb
|
40
|
+
- test/collection_test.rb
|
41
|
+
- test/lib/view_test_process.rb
|
42
|
+
- test/test_helper.rb
|
43
|
+
- test/view_helpers_test.rb
|
44
|
+
has_rdoc: true
|
45
|
+
homepage: http://github.com/objectreload/pagination
|
46
|
+
licenses: []
|
47
|
+
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options:
|
50
|
+
- --charset=UTF-8
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
requirements: []
|
66
|
+
|
67
|
+
rubyforge_project:
|
68
|
+
rubygems_version: 1.3.5
|
69
|
+
signing_key:
|
70
|
+
specification_version: 3
|
71
|
+
summary: Simple pagination - without changes in controllers
|
72
|
+
test_files:
|
73
|
+
- test/test_helper.rb
|
74
|
+
- test/lib/view_test_process.rb
|
75
|
+
- test/active_record_extentions_test.rb
|
76
|
+
- test/collection_test.rb
|
77
|
+
- test/view_helpers_test.rb
|