require 'builder'
module Merb
module MerbAdmin
module MainHelper
def object_title(object)
object.try(:name) || object.try(:title) || "#{object.class.to_s} ##{object.id}"
end
# Given a page count and the current page, we generate a set of pagination
# links.
#
# * We use an inner and outer window into a list of links. For a set of
# 20 pages with the current page being 10:
# outer_window:
# 1 2 ..... 19 20
# inner_window
# 5 6 7 8 9 10 11 12 13 14
#
# This is totally adjustable, or can be turned off by giving the
# :inner_window setting a value of nil.
#
# * Options
# :left_cut_label => text_for_cut::
# Used when the page numbers need to be cut off to prevent the set of
# pagination links from being too long.
# Defaults to '…'
# :right_cut_label => text_for_cut::
# Same as :left_cut_label but for the right side of numbers.
# Defaults to '…'
# :outer_window => number_of_pages::
# Sets the number of pages to include in the outer 'window'
# Defaults to 2
# :inner_window => number_of_pages::
# Sets the number of pags to include in the inner 'window'
# Defaults to 7
# :page_param => name_of_page_paramiter
# Sets the name of the paramiter the paginator uses to return what
# page is being requested.
# Defaults to 'page'
# :url => url_for_links
# Provides the base url to use in the page navigation links.
# Defaults to ''
def paginate(current_page, page_count, options = {})
options.reverse_merge!({
:left_cut_label => '…',
:right_cut_label => '…',
:outer_window => 2,
:inner_window => 7,
:page_param => 'page',
:url => ''
})
url = options.delete :url
url << (url.include?('?') ? '&' : '?') << options[:page_param]
pages = {
:all => (1..page_count).to_a,
:left => [],
:center => [],
:right => []
}
# Only worry about using our 'windows' if the page count is less then
# our windows combined.
if options[:inner_window].nil? || ((options[:outer_window] * 2) + options[:inner_window] + 2) >= page_count
pages[:center] = pages[:all]
else
pages[:left] = pages[:all][0, options[:outer_window]]
pages[:right] = pages[:all][page_count - options[:outer_window], options[:outer_window]]
pages[:center] = case current_page
# allow the inner 'window' to shift to right when close to the left edge
# Ex: 1 2 [3] 4 5 6 7 8 9 ... 20
when -infinity .. (options[:inner_window] / 2) + 3
pages[:all][options[:outer_window], options[:inner_window]] +
[options[:right_cut_label]]
# allow the inner 'window' to shift left when close to the right edge
# Ex: 1 2 ... 12 13 14 15 16 [17] 18 19 20
when (page_count - (options[:inner_window] / 2.0).ceil) - 1 .. infinity
[options[:left_cut_label]] +
pages[:all][page_count - options[:inner_window] - options[:outer_window], options[:inner_window]]
# Display the unshifed window
# ex: 1 2 ... 5 6 7 [8] 9 10 11 ... 19 20
else
[options[:left_cut_label]] +
pages[:all][current_page - (options[:inner_window] / 2) - 1, options[:inner_window]] +
[options[:right_cut_label]]
end
end
b = []
[pages[:left], pages[:center], pages[:right]].each do |p|
p.each do |page_number|
case page_number
when String
b << page_number
when current_page
b << Builder::XmlMarkup.new.span(page_number, :class => "this-page")
when page_count
b << Builder::XmlMarkup.new.a(page_number, :class => "end", :href => "#{url}=#{page_number}")
else
b << Builder::XmlMarkup.new.a(page_number, :href => "#{url}=#{page_number}")
end
end
end
b.join(" ")
end
private
def infinity
1.0 / 0
end
end
end
end