Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 329 lines (296 sloc) 12.851 kB
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
1 require 'will_paginate/core_ext'
b40c221 Reorganize the complete will_paginate loading process to be modular. …
mislav authored
2
cce713c move will_paginate files around so rails auto-loading doesnt get conf…
chris authored
3 module WillPaginate
138f004 Will Paginate Christmas doc love
mislav authored
4 # = Will Paginate view helpers
5 #
6 # Currently there is only one view helper: +will_paginate+. It renders the
7 # pagination links for the given collection. The helper itself is lightweight
8 # and serves only as a wrapper around link renderer instantiation; the
9 # renderer then does all the hard work of generating the HTML.
10 #
11 # == Global options for helpers
190a3b3 Will Paginate: save global defaults for view helpers in easily access…
mislav authored
12 #
13 # Options for pagination helpers are optional and get their default values from the
14 # WillPaginate::ViewHelpers.pagination_options hash. You can write to this hash to
15 # override default options on the global level:
16 #
17 # WillPaginate::ViewHelpers.pagination_options[:prev_label] = 'Previous page'
18 #
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
19 # By putting this into your environment.rb you can easily translate link texts to previous
190a3b3 Will Paginate: save global defaults for view helpers in easily access…
mislav authored
20 # and next pages, as well as override some other defaults to your liking.
cce713c move will_paginate files around so rails auto-loading doesnt get conf…
chris authored
21 module ViewHelpers
ba2d2cc Will Paingate dox spellcheck ftw
mislav authored
22 # default options that can be overridden on the global level
138f004 Will Paginate Christmas doc love
mislav authored
23 @@pagination_options = {
24 :class => 'pagination',
25 :prev_label => '« Previous',
26 :next_label => 'Next »',
27 :inner_window => 4, # links around the current page
28 :outer_window => 1, # links around beginning and end
29 :separator => ' ', # single space is friendly to spiders and non-graphic browsers
30 :param_name => :page,
31 :params => nil,
0e5528b Will Paginate now has the option to disable rendering of page links (…
mislav authored
32 :renderer => 'WillPaginate::LinkRenderer',
33 :page_links => true,
34 :container => true
138f004 Will Paginate Christmas doc love
mislav authored
35 }
190a3b3 Will Paginate: save global defaults for view helpers in easily access…
mislav authored
36 mattr_reader :pagination_options
ac36b02 Slight finder rewrite (yeah, again ^^). PaginatedCollection is now Co…
mislav authored
37
138f004 Will Paginate Christmas doc love
mislav authored
38 # Renders Digg/Flickr-style pagination for a WillPaginate::Collection
39 # object. Nil is returned if there is only one page in total; no point in
40 # rendering the pagination in that case...
8ee293e Bunch of nice stuff: bugfix, docs, cleanup, test/console.
mislav authored
41 #
138f004 Will Paginate Christmas doc love
mislav authored
42 # ==== Options
43 # * <tt>:class</tt> -- CSS class name for the generated DIV (default: "pagination")
44 # * <tt>:prev_label</tt> -- default: "« Previous"
45 # * <tt>:next_label</tt> -- default: "Next »"
46 # * <tt>:inner_window</tt> -- how many links are shown around the current page (default: 4)
47 # * <tt>:outer_window</tt> -- how many links are around the first and the last page (default: 1)
48 # * <tt>:separator</tt> -- string separator for page HTML elements (default: single space)
49 # * <tt>:param_name</tt> -- parameter name for page number in URLs (default: <tt>:page</tt>)
50 # * <tt>:params</tt> -- additional parameters when generating pagination links
51 # (eg. <tt>:controller => "foo", :action => nil</tt>)
52 # * <tt>:renderer</tt> -- class name of the link renderer (default: WillPaginate::LinkRenderer)
0e5528b Will Paginate now has the option to disable rendering of page links (…
mislav authored
53 # * <tt>:page_links</tt> -- when false, only previous/next links are rendered (default: true)
54 # * <tt>:container</tt> -- toggles rendering of the DIV container for pagination links, set to
55 # false only when you are rendering your own pagination markup (default: true)
a14d2da Will Paginate can generate an HTML ID for the pagination container au…
mislav authored
56 # * <tt>:id</tt> -- HTML ID for the container (default: nil). Pass +true+ to have the ID automatically
57 # generated from the class name of objects in collection: for example, paginating
58 # ArticleComment models would yield an ID of "article_comments_pagination".
8ee293e Bunch of nice stuff: bugfix, docs, cleanup, test/console.
mislav authored
59 #
b4b4f19 Will Paginate BACKWARDS INCOMPATIBLE CHANGE: POST parameters are no l…
mislav authored
60 # All options beside listed ones are passed as HTML attributes to the container
61 # element for pagination links (the DIV). For example:
62 #
63 # <%= will_paginate @posts, :id => 'wp_posts' %>
64 #
65 # ... will result in:
66 #
67 # <div class="pagination" id="wp_posts"> ... </div>
cce713c move will_paginate files around so rails auto-loading doesnt get conf…
chris authored
68 #
138f004 Will Paginate Christmas doc love
mislav authored
69 # ==== Using the helper without arguments
70 # If the helper is called without passing in the collection object, it will
71 # try to read from the instance variable inferred by the controller name.
72 # For example, calling +will_paginate+ while the current controller is
73 # PostsController will result in trying to read from the <tt>@posts</tt>
95f0351 Will Paginate: option hash can be passed for as the first argument
mislav authored
74 # variable. Example:
75 #
76 # <%= will_paginate :id => true %>
77 #
78 # ... will result in <tt>@post</tt> collection getting paginated:
79 #
80 # <div class="pagination" id="posts_pagination"> ... </div>
138f004 Will Paginate Christmas doc love
mislav authored
81 #
e757537 Will Paginate: add support for custom renderers. Polish the API for W…
mislav authored
82 def will_paginate(collection = nil, options = {})
95f0351 Will Paginate: option hash can be passed for as the first argument
mislav authored
83 options, collection = collection, nil if collection.is_a? Hash
138f004 Will Paginate Christmas doc love
mislav authored
84 unless collection or !controller
85 collection_name = "@#{controller.controller_name}"
86 collection = instance_variable_get(collection_name)
87 raise ArgumentError, "The #{collection_name} variable appears to be empty. Did you " +
44fe4cc @mislav doc love all around
authored
88 "forget to pass the collection object for will_paginate?" unless collection
138f004 Will Paginate Christmas doc love
mislav authored
89 end
e757537 Will Paginate: add support for custom renderers. Polish the API for W…
mislav authored
90 # early exit if there is nothing to render
5bd4767 @mislav deprecation notices if you use a collection that responds to old `pag…
authored
91 return nil unless WillPaginate::ViewHelpers.total_pages_for_collection(collection) > 1
92
e757537 Will Paginate: add support for custom renderers. Polish the API for W…
mislav authored
93 options = options.symbolize_keys.reverse_merge WillPaginate::ViewHelpers.pagination_options
94 # create the renderer instance
95 renderer_class = options[:renderer].to_s.constantize
96 renderer = renderer_class.new collection, options, self
97 # render HTML for pagination
0e5528b Will Paginate now has the option to disable rendering of page links (…
mislav authored
98 renderer.to_html
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
99 end
990e06d @mislav with_pagination( @collection, {} ) view helper for DRYing up header a…
authored
100
2597848 @mislav rename with_pagination to paginated_section and add better docs and t…
authored
101 # Wrapper for rendering pagination links at both top and bottom of a block
102 # of content.
103 #
104 # <% paginated_section @posts do %>
44fe4cc @mislav doc love all around
authored
105 # <ol id="posts">
2597848 @mislav rename with_pagination to paginated_section and add better docs and t…
authored
106 # <% for post in @posts %>
107 # <li> ... </li>
108 # <% end %>
109 # </ol>
110 # <% end %>
111 #
44fe4cc @mislav doc love all around
authored
112 # will result in:
113 #
114 # <div class="pagination"> ... </div>
115 # <ol id="posts">
116 # ...
117 # </ol>
118 # <div class="pagination"> ... </div>
119 #
2597848 @mislav rename with_pagination to paginated_section and add better docs and t…
authored
120 # Arguments are passed to a <tt>will_paginate</tt> call, so the same options
121 # apply. Don't use the <tt>:id</tt> option; otherwise you'll finish with two
122 # blocks of pagination links sharing the same ID (which is invalid HTML).
123 def paginated_section(*args, &block)
5bd4767 @mislav deprecation notices if you use a collection that responds to old `pag…
authored
124 pagination = will_paginate(*args).to_s
2597848 @mislav rename with_pagination to paginated_section and add better docs and t…
authored
125 content = pagination + capture(&block) + pagination
126 concat content, block.binding
127 end
21472a8 Add page_entries_info view helper
mislav authored
128
129 # Renders a helpful message with numbers of displayed vs. total entries.
130 # You can use this as a blueprint for your own, similar helpers.
131 #
132 # <%= page_entries_info @posts %>
133 # #-> Displaying entries 6 - 10 of 26 in total
134 def page_entries_info(collection)
cc1516d @mislav Change output of "page_entries_info" on single-page collection and er…
authored
135 if collection.total_pages < 2
136 case collection.size
137 when 0; 'No entries found'
138 when 1; 'Displaying <b>1</b> entry'
139 else; "Displaying <b>all #{collection.size}</b> entries"
140 end
141 else
142 %{Displaying entries <b>%d&nbsp;-&nbsp;%d</b> of <b>%d</b> in total} % [
143 collection.offset + 1,
144 collection.offset + collection.length,
145 collection.total_entries
146 ]
147 end
21472a8 Add page_entries_info view helper
mislav authored
148 end
5bd4767 @mislav deprecation notices if you use a collection that responds to old `pag…
authored
149
150 def self.total_pages_for_collection(collection) #:nodoc:
5ec1aca @mislav use strings in "respond_to?" calls to work around a bug in acts_as_fe…
authored
151 if collection.respond_to?('page_count') and !collection.respond_to?('total_pages')
5bd4767 @mislav deprecation notices if you use a collection that responds to old `pag…
authored
152 WillPaginate::Deprecation.warn <<-MSG
153 You are using a paginated collection of class #{collection.class.name}
154 which conforms to the old API of WillPaginate::Collection by using
155 `page_count`, while the current method name is `total_pages`. Please
44fe4cc @mislav doc love all around
authored
156 upgrade yours or 3rd-party code that provides the paginated collection.
5bd4767 @mislav deprecation notices if you use a collection that responds to old `pag…
authored
157 MSG
158 class << collection
159 def total_pages; page_count; end
160 end
161 end
162 collection.total_pages
163 end
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
164 end
ed3744f Will Paginate: view helper optimization
mislav authored
165
286fa0f Dox tweaks + link to Railscast
mislav authored
166 # This class does the heavy lifting of actually building the pagination
21472a8 Add page_entries_info view helper
mislav authored
167 # links. It is used by +will_paginate+ helper internally.
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
168 class LinkRenderer
44fe4cc @mislav doc love all around
authored
169 # * +collection+ is a WillPaginate::Collection instance or any other object
170 # that conforms to that API
171 # * +options+ are forwarded from +will_paginate+ view helper
172 # * +template+ is the reference to the template being rendered
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
173 def initialize(collection, options, template)
174 @collection = collection
e757537 Will Paginate: add support for custom renderers. Polish the API for W…
mislav authored
175 @options = options
176 @template = template
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
177 end
178
44fe4cc @mislav doc love all around
authored
179 # Process it! This method returns the complete HTML string which contains
180 # pagination links. Feel free to subclass LinkRenderer and change this
181 # method as you see fit.
e757537 Will Paginate: add support for custom renderers. Polish the API for W…
mislav authored
182 def to_html
b21179c Break LinkRenderer#windowed_paginator into 2 methods: `windowed_links…
mislav authored
183 links = @options[:page_links] ? windowed_links : []
0e5528b Will Paginate now has the option to disable rendering of page links (…
mislav authored
184 # previous/next buttons
3bda0ba @mislav added prev_page/next_page CSS classes on prev/next "buttons" in views
authored
185 links.unshift page_link_or_span(@collection.previous_page, %w(disabled prev_page), @options[:prev_label])
186 links.push page_link_or_span(@collection.next_page, %w(disabled next_page), @options[:next_label])
0e5528b Will Paginate now has the option to disable rendering of page links (…
mislav authored
187
188 html = links.join(@options[:separator])
189 @options[:container] ? @template.content_tag(:div, html, html_attributes) : html
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
190 end
191
44fe4cc @mislav doc love all around
authored
192 # Returns the subset of +options+ this instance was initialized with that
193 # represent HTML attributes for the container element of pagination links.
e757537 Will Paginate: add support for custom renderers. Polish the API for W…
mislav authored
194 def html_attributes
0e5528b Will Paginate now has the option to disable rendering of page links (…
mislav authored
195 return @html_attributes if @html_attributes
196 @html_attributes = @options.except *(WillPaginate::ViewHelpers.pagination_options.keys - [:class])
a14d2da Will Paginate can generate an HTML ID for the pagination container au…
mislav authored
197 # pagination of Post models will have the ID of "posts_pagination"
198 if @options[:container] and @options[:id] === true
199 @html_attributes[:id] = @collection.first.class.name.underscore.pluralize + '_pagination'
200 end
0e5528b Will Paginate now has the option to disable rendering of page links (…
mislav authored
201 @html_attributes
cce713c move will_paginate files around so rails auto-loading doesnt get conf…
chris authored
202 end
203
204 protected
205
44fe4cc @mislav doc love all around
authored
206 # The gap in page links is represented by:
207 #
208 # <span class="gap">&hellip;</span>
3f770b7 @mislav Change gap in pagination links from '...' to '<span class="gap">&hell…
authored
209 def gap_marker
210 '<span class="gap">&hellip;</span>'
211 end
a9645f8 Simplify page link gaps and add tests for them. Added LinkRenderer#ga…
mislav authored
212
44fe4cc @mislav doc love all around
authored
213 # Collects link items for visible page numbers.
b21179c Break LinkRenderer#windowed_paginator into 2 methods: `windowed_links…
mislav authored
214 def windowed_links
215 prev = nil
216
217 visible_page_numbers.inject [] do |links, n|
218 # detect gaps:
219 links << gap_marker if prev and n > prev + 1
3bda0ba @mislav added prev_page/next_page CSS classes on prev/next "buttons" in views
authored
220 links << page_link_or_span(n, 'current')
b21179c Break LinkRenderer#windowed_paginator into 2 methods: `windowed_links…
mislav authored
221 prev = n
222 links
223 end
224 end
225
44fe4cc @mislav doc love all around
authored
226 # Calculates visible page numbers using the <tt>:inner_window</tt> and
227 # <tt>:outer_window</tt> options.
b21179c Break LinkRenderer#windowed_paginator into 2 methods: `windowed_links…
mislav authored
228 def visible_page_numbers
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
229 inner_window, outer_window = @options[:inner_window].to_i, @options[:outer_window].to_i
3c594b1 Will Paginate: simplify gap logic while rendering page links. Elimina…
mislav authored
230 window_from = current_page - inner_window
231 window_to = current_page + inner_window
232
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
233 # adjust lower or upper limit if other is out of bounds
3c594b1 Will Paginate: simplify gap logic while rendering page links. Elimina…
mislav authored
234 if window_to > total_pages
235 window_from -= window_to - total_pages
236 window_to = total_pages
f4a2320 @mislav test with rcov and bring it up to 100% test coverage (yeah!!)
authored
237 end
238 if window_from < 1
3c594b1 Will Paginate: simplify gap logic while rendering page links. Elimina…
mislav authored
239 window_to += 1 - window_from
240 window_from = 1
f4a2320 @mislav test with rcov and bring it up to 100% test coverage (yeah!!)
authored
241 window_to = total_pages if window_to > total_pages
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
242 end
243
3c594b1 Will Paginate: simplify gap logic while rendering page links. Elimina…
mislav authored
244 visible = (1..total_pages).to_a
245 left_gap = (2 + outer_window)...window_from
246 right_gap = (window_to + 1)...(total_pages - outer_window)
247 visible -= left_gap.to_a if left_gap.last - left_gap.first > 1
248 visible -= right_gap.to_a if right_gap.last - right_gap.first > 1
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
249
b21179c Break LinkRenderer#windowed_paginator into 2 methods: `windowed_links…
mislav authored
250 visible
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
251 end
b21179c Break LinkRenderer#windowed_paginator into 2 methods: `windowed_links…
mislav authored
252
3bda0ba @mislav added prev_page/next_page CSS classes on prev/next "buttons" in views
authored
253 def page_link_or_span(page, span_class, text = nil)
3c594b1 Will Paginate: simplify gap logic while rendering page links. Elimina…
mislav authored
254 text ||= page.to_s
3bda0ba @mislav added prev_page/next_page CSS classes on prev/next "buttons" in views
authored
255 classnames = Array[*span_class]
256
3c594b1 Will Paginate: simplify gap logic while rendering page links. Elimina…
mislav authored
257 if page and page != current_page
f48248f @mislav rename LinkRenderer#url_params to #url_for and drastically optimize it
authored
258 @template.link_to text, url_for(page), :rel => rel_value(page), :class => classnames[1]
b97360d Page link for page 1 doesn't render with :page parameter anymore. Thi…
mislav authored
259 else
3bda0ba @mislav added prev_page/next_page CSS classes on prev/next "buttons" in views
authored
260 @template.content_tag :span, text, :class => classnames.join(' ')
b97360d Page link for page 1 doesn't render with :page parameter anymore. Thi…
mislav authored
261 end
cce713c move will_paginate files around so rails auto-loading doesnt get conf…
chris authored
262 end
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
263
44fe4cc @mislav doc love all around
authored
264 # Returns URL params for +page_link_or_span+, taking the current GET params
265 # and <tt>:params</tt> option into account.
f48248f @mislav rename LinkRenderer#url_params to #url_for and drastically optimize it
authored
266 def url_for(page)
267 unless @url_string
268 @url_params = { :escape => false }
342b042 @mislav Rename LinkRenderer#url_options to `url_params` and refactor it for s…
authored
269 # page links should preserve GET parameters
270 stringified_merge @url_params, @template.params if @template.request.get?
271 stringified_merge @url_params, @options[:params] if @options[:params]
272
273 if param_name.index(/[^\w-]/)
f4a2320 @mislav test with rcov and bring it up to 100% test coverage (yeah!!)
authored
274 page_param = (defined?(CGIMethods) ? CGIMethods : ActionController::AbstractRequest).
275 parse_query_parameters("#{param_name}=#{page}")
342b042 @mislav Rename LinkRenderer#url_options to `url_params` and refactor it for s…
authored
276
277 stringified_merge @url_params, page_param
f48248f @mislav rename LinkRenderer#url_params to #url_for and drastically optimize it
authored
278 else
279 @url_params[param_name] = page
342b042 @mislav Rename LinkRenderer#url_options to `url_params` and refactor it for s…
authored
280 end
f48248f @mislav rename LinkRenderer#url_params to #url_for and drastically optimize it
authored
281
282 url = @template.url_for(@url_params)
283 @url_string = url.sub(/([?&]#{CGI.escape param_name}=)#{page}/, '\1@')
284 return url
342b042 @mislav Rename LinkRenderer#url_options to `url_params` and refactor it for s…
authored
285 end
f48248f @mislav rename LinkRenderer#url_params to #url_for and drastically optimize it
authored
286 @url_string.sub '@', page.to_s
b4b4f19 Will Paginate BACKWARDS INCOMPATIBLE CHANGE: POST parameters are no l…
mislav authored
287 end
288
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
289 private
290
8a906a2 @mislav Add rel="prev|next|start" to page links. Closes #196 [swdyh]
authored
291 def rel_value(page)
292 case page
293 when @collection.previous_page; 'prev' + (page == 1 ? ' start' : '')
294 when @collection.next_page; 'next'
295 when 1; 'start'
296 end
297 end
298
b4b4f19 Will Paginate BACKWARDS INCOMPATIBLE CHANGE: POST parameters are no l…
mislav authored
299 def current_page
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
300 @collection.current_page
301 end
302
303 def total_pages
5bd4767 @mislav deprecation notices if you use a collection that responds to old `pag…
authored
304 @total_pages ||= WillPaginate::ViewHelpers.total_pages_for_collection(@collection)
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
305 end
306
b4b4f19 Will Paginate BACKWARDS INCOMPATIBLE CHANGE: POST parameters are no l…
mislav authored
307 def param_name
342b042 @mislav Rename LinkRenderer#url_options to `url_params` and refactor it for s…
authored
308 @param_name ||= @options[:param_name].to_s
b4b4f19 Will Paginate BACKWARDS INCOMPATIBLE CHANGE: POST parameters are no l…
mislav authored
309 end
310
342b042 @mislav Rename LinkRenderer#url_options to `url_params` and refactor it for s…
authored
311 def stringified_merge(target, other)
312 other.each do |key, value|
313 key = key.to_s
314 existing = target[key]
8fe31cb @mislav finish transitioning pagination_test.rb to view_test.rb; caught and f…
authored
315
316 if value.is_a?(Hash)
317 target[key] = existing = {} if existing.nil?
318 if existing.is_a?(Hash)
319 stringified_merge(existing, value)
320 return
321 end
342b042 @mislav Rename LinkRenderer#url_options to `url_params` and refactor it for s…
authored
322 end
8fe31cb @mislav finish transitioning pagination_test.rb to view_test.rb; caught and f…
authored
323
324 target[key] = value
342b042 @mislav Rename LinkRenderer#url_options to `url_params` and refactor it for s…
authored
325 end
7ec87d2 Refactor will_paginate helper to WillPaginate::LinkRenderer class to …
mislav authored
326 end
cce713c move will_paginate files around so rails auto-loading doesnt get conf…
chris authored
327 end
328 end
Something went wrong with that request. Please try again.