Pastie now auto-senses if line-wrap is a bad or good idea. Feedback?
## mark a section (Learn more)
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
This paste will be private.
From the Design Piracy series on my blog: