module WillPaginate
# = Global options for pagination helpers
#
# Options for pagination helpers are optional and get their default values from the
# WillPaginate::ViewHelpers.pagination_options hash. You can write to this hash to
# override default options on the global level:
#
# WillPaginate::ViewHelpers.pagination_options[:prev_label] = 'Previous page'
#
# By putting this into your environment.rb you can easily localize link texts to previous
# and next pages, as well as override some other defaults to your liking.
module ViewHelpers
# default options that can be overriden on the global level
@@pagination_options = { :class => 'pagination',
:prev_label => '« Previous',
:next_label => 'Next »',
:inner_window => 4, # links around the current page
:outer_window => 1, # links around beginning and end
:separator => ' ', # single space is friendly to spiders and non-graphic browsers
:param_name => :page,
:remote_options => {},
:remote_html_options => {}
}
mattr_reader :pagination_options
# Renders Digg-style pagination. (We know you wanna!)
# Returns nil if there is only one page in total (can't paginate that).
#
# Options for will_paginate view helper:
#
# class: CSS class name for the generated DIV (default "pagination")
# prev_label: default '« Previous',
# next_label: default 'Next »',
# inner_window: how many links are shown around the current page, defaults to 4
# outer_window: how many links are around the first and the last page, defaults to 1
# separator: string separator for page HTML elements, default " " (single space)
# param_name: parameter name for page number in URLs, defaults to "page"
# remote_options: options for link_to_remote. If not empty you get a link_to_remote with these options instead of the classic link. default is empty.
# remote_html_options: html_options for link_to_remote, default is empty.
#
# All extra options are passed to the generated container DIV, so eventually
# they become its HTML attributes.
#
def will_paginate(entries = @entries, options = {})
total_pages = entries.page_count
if total_pages > 1
options = options.symbolize_keys.reverse_merge(pagination_options)
page= entries.current_page
param = Hash.new
param[:param_name]= options.delete :param_name
param[:remote_options]= options.delete :remote_options
param[:remote_html_options]= options.delete :remote_html_options
inner_window, outer_window = options.delete(:inner_window).to_i, options.delete(:outer_window).to_i
min = page - inner_window
max = page + inner_window
# adjust lower or upper limit if other is out of bounds
if max > total_pages then min -= max - total_pages
elsif min < 1 then max += 1 - min
end
current = min..max
beginning = 1..(1 + outer_window)
tail = (total_pages - outer_window)..total_pages
visible = [beginning, current, tail].map(&:to_a).flatten.sort.uniq
links, prev = [], 0
visible.each do |n|
next if n < 1
break if n > total_pages
unless n - prev > 1
prev = n
links << page_link_or_span((n != page ? n : nil), 'current', n, param)
else
# ellipsis represents the gap between windows
prev = n - 1
links << '...'
redo
end
end
# next and previous buttons
links.unshift page_link_or_span(entries.previous_page, 'disabled', options.delete(:prev_label), param)
links.push page_link_or_span(entries.next_page, 'disabled', options.delete(:next_label), param)
content_tag :div, links.join(options.delete(:separator)), options
end
end
protected
def page_link_or_span(page, span_class, text, param)
unless page
content_tag :span, text, :class => span_class
else
# page links should preserve GET parameters, so we merge params
if param[:remote_options].empty?
link_to text, params.merge(param[:param_name].to_sym => (page !=1 ? page : nil))
else
# Merge params and put page number even if page is 1. So if you have multiple ajax will_paginate on the
# same action, you know which one you have to render, ex :
# format.js {
# if params[:page_line_items]
# render :partial => "line_items"
# elsif params[:page_packages]
# render :partial => "packages"
# end
# }
param[:remote_options][:url] = {:params => params.merge(param[:param_name].to_sym => page)}
# If javascript is disabled, you'll still have your pagination working
param[:remote_html_options][:href] = url_for(params.merge(param[:param_name].to_sym => (page !=1 ? page : nil)))
link_to_remote text, param[:remote_options], param[:remote_html_options]
end
end
end
end
end