Index: lib/will_paginate.rb
===================================================================
--- lib/will_paginate.rb (revision 120)
+++ lib/will_paginate.rb (working copy)
@@ -1,43 +1,51 @@
module WillPaginate
- def will_paginate(total_count, per_page, page = @page)
- adjacents = 2
- prev_page = page - 1
- next_page = page + 1
- last_page = (total_count / per_page.to_f).ceil
- lpm1 = last_page - 1
+ def will_paginate(total_count, per_page, page = @page, options = {})
+ total = (total_count / per_page.to_f).ceil
- returning '' do |pgn|
- if last_page > 1
- pgn << %{<div class="pagination">}
-
- # not enough pages to bother breaking
- if last_page < 7 + (adjacents * 2)
- 1.upto(last_page) { |ctr| pgn << (ctr == page ? content_tag(:span, ctr, :class => 'current') : link_to(ctr, :page => ctr)) }
-
- # enough pages to hide some
- elsif last_page > 5 + (adjacents * 2)
-
- # close to beginning, only hide later pages
- if page < 1 + (adjacents * 2)
- 1.upto(3 + (adjacents * 2)) { |ctr| pgn << (ctr == page ? content_tag(:span, ctr, :class => 'current') : link_to(ctr, :page => ctr)) }
- pgn << "..." + link_to(lpm1, :page => lpm1) + link_to(last_page, :page => last_page)
-
- # in middle, hide some from both sides
- elsif last_page - (adjacents * 2) > page && page > (adjacents * 2)
- pgn << link_to('1', :page => 1) + link_to('2', :page => 2) + "..."
- (page - adjacents).upto(page + adjacents) { |ctr| pgn << (ctr == page ? content_tag(:span, ctr, :class => 'current') : link_to(ctr, :page => ctr)) }
- pgn << "..." + link_to(lpm1, :page => lpm1) + link_to(last_page, :page => last_page)
-
- # close to end, only hide early pages
- else
- pgn << link_to('1', :page => 1) + link_to('2', :page => 2) + "..."
- (last_page - (2 + (adjacents * 2))).upto(last_page) { |ctr| pgn << (ctr == page ? content_tag(:span, ctr, :class => 'current') : link_to(ctr, :page => ctr)) }
- end
+ if total > 1
+ options = options.reverse_merge :class => 'pagination',
+ :prev_label => '« Previous',
+ :next_label => 'Next »',
+ :inner_offset => 4, # links around the current page
+ :outer_offset => 1 # links around beginning and end
+
+ inner_offset, outer_offset = options.delete(:inner_offset), options.delete(:outer_offset)
+
+ min = page - inner_offset
+ max = page + inner_offset
+
+ # adjust lower or upper limit if other is out of bounds
+ if max > total then min -= max - total
+ elsif min < 1 then max += 1 - min
+ end
+
+ current = min..max
+ beginning = 1..(1+outer_offset)
+ tail = (total-outer_offset)..total
+ visible = [current, beginning, tail].map(&:to_a).sum
+
+ def link_or_span(target, condition, span_class = nil, text = target.to_s)
+ condition ? content_tag(:span, text, :class => span_class) :
+ link_to(text, :page => target)
+ end
+
+ # build the list of the links
+ links = (1..total).inject([]) do |list, n|
+ if visible.include? n
+ list << link_or_span(n, n == page, 'current')
+ elsif n == beginning.last + 1 || n == tail.first - 1
+ list << '...'
end
- pgn << (page > 1 ? link_to("« Previous", :page => prev_page) : content_tag(:span, "« Previous", :class => 'disabled'))
- pgn << (page < last_page ? link_to("Next »", :page => next_page) : content_tag(:span, "Next »", :class => 'disabled'))
- pgn << '</div>'
+ list
end
+
+ prev,succ = page-1, page+1
+ links.unshift link_or_span(prev, prev.zero?, 'disabled', options.delete(:prev_label))
+ links.push link_or_span(succ, succ > total, 'disabled', options.delete(:next_label))
+
+ content_tag :div, links.join(' '), options
+ else
+ nil
end
end
end
Index: lib/finder.rb
===================================================================
--- lib/finder.rb (revision 120)
+++ lib/finder.rb (working copy)
@@ -7,23 +7,22 @@
define_method(:per_page) { 30 } unless respond_to? :per_page
end
end
-
+
module ClassMethods
- def method_missing_with_will_paginate(method_id, *args, &block)
- unless match = /^paginate/.match(method_id.to_s)
- return method_missing_without_will_paginate(method_id, *args, &block)
+ def method_missing_with_will_paginate(method, *args, &block)
+ unless match = /^paginate/.match(method.to_s)
+ return method_missing_without_will_paginate(method, *args, &block)
end
-
- options = args.last.is_a?(Hash) ? args.pop : {}
- page = options[:page].to_i.zero? ? 1 : options[:page].to_i
- options.delete(:page)
- limit_per_page = options[:per_page] || per_page
- options.delete(:per_page)
- args << options
-
- with_scope :find => { :offset => (page - 1) * limit_per_page, :limit => limit_per_page } do
- [send(method_id.to_s.sub(/^paginate/, 'find'), *args), page]
+
+ if (options = args.last).is_a? Hash
+ page = options[:page].to_i.zero? ? 1 : options[:page].to_i
+ options.delete(:page)
+ entries_per_page = options.delete(:per_page) || per_page
end
+
+ with_scope :find => { :offset => (page - 1) * limit_per_page, :limit => entries_per_page } do
+ [send(method.to_s.sub(/^paginate/, 'find'), *args), page]
+ end
end
end
end