Chris@909: module ActionView Chris@909: module Helpers Chris@909: # Provides methods for linking to ActionController::Pagination objects using a simple generator API. You can optionally Chris@909: # also build your links manually using ActionView::Helpers::AssetHelper#link_to like so: Chris@909: # Chris@909: # <%= link_to "Previous page", { :page => paginator.current.previous } if paginator.current.previous %> Chris@909: # <%= link_to "Next page", { :page => paginator.current.next } if paginator.current.next %> Chris@909: module PaginationHelper Chris@909: unless const_defined?(:DEFAULT_OPTIONS) Chris@909: DEFAULT_OPTIONS = { Chris@909: :name => :page, Chris@909: :window_size => 2, Chris@909: :always_show_anchors => true, Chris@909: :link_to_current_page => false, Chris@909: :params => {} Chris@909: } Chris@909: end Chris@909: Chris@909: # Creates a basic HTML link bar for the given +paginator+. Links will be created Chris@909: # for the next and/or previous page and for a number of other pages around the current Chris@909: # pages position. The +html_options+ hash is passed to +link_to+ when the links are created. Chris@909: # Chris@909: # ==== Options Chris@909: # :name:: the routing name for this paginator Chris@909: # (defaults to +page+) Chris@909: # :prefix:: prefix for pagination links Chris@909: # (i.e. Older Pages: 1 2 3 4) Chris@909: # :suffix:: suffix for pagination links Chris@909: # (i.e. 1 2 3 4 <- Older Pages) Chris@909: # :window_size:: the number of pages to show around Chris@909: # the current page (defaults to 2) Chris@909: # :always_show_anchors:: whether or not the first and last Chris@909: # pages should always be shown Chris@909: # (defaults to +true+) Chris@909: # :link_to_current_page:: whether or not the current page Chris@909: # should be linked to (defaults to Chris@909: # +false+) Chris@909: # :params:: any additional routing parameters Chris@909: # for page URLs Chris@909: # Chris@909: # ==== Examples Chris@909: # # We'll assume we have a paginator setup in @person_pages... Chris@909: # Chris@909: # pagination_links(@person_pages) Chris@909: # # => 1 2 3 ... 10 Chris@909: # Chris@909: # pagination_links(@person_pages, :link_to_current_page => true) Chris@909: # # => 1 2 3 ... 10 Chris@909: # Chris@909: # pagination_links(@person_pages, :always_show_anchors => false) Chris@909: # # => 1 2 3 Chris@909: # Chris@909: # pagination_links(@person_pages, :window_size => 1) Chris@909: # # => 1 2 ... 10 Chris@909: # Chris@909: # pagination_links(@person_pages, :params => { :viewer => "flash" }) Chris@909: # # => 1 2 3 ... Chris@909: # # 10 Chris@909: def pagination_links(paginator, options={}, html_options={}) Chris@909: name = options[:name] || DEFAULT_OPTIONS[:name] Chris@909: params = (options[:params] || DEFAULT_OPTIONS[:params]).clone Chris@909: Chris@909: prefix = options[:prefix] || '' Chris@909: suffix = options[:suffix] || '' Chris@909: Chris@909: pagination_links_each(paginator, options, prefix, suffix) do |n| Chris@909: params[name] = n Chris@909: link_to(n.to_s, params, html_options) Chris@909: end Chris@909: end Chris@909: Chris@909: # Iterate through the pages of a given +paginator+, invoking a Chris@909: # block for each page number that needs to be rendered as a link. Chris@909: # Chris@909: # ==== Options Chris@909: # :window_size:: the number of pages to show around Chris@909: # the current page (defaults to +2+) Chris@909: # :always_show_anchors:: whether or not the first and last Chris@909: # pages should always be shown Chris@909: # (defaults to +true+) Chris@909: # :link_to_current_page:: whether or not the current page Chris@909: # should be linked to (defaults to Chris@909: # +false+) Chris@909: # Chris@909: # ==== Example Chris@909: # # Turn paginated links into an Ajax call Chris@909: # pagination_links_each(paginator, page_options) do |link| Chris@909: # options = { :url => {:action => 'list'}, :update => 'results' } Chris@909: # html_options = { :href => url_for(:action => 'list') } Chris@909: # Chris@909: # link_to_remote(link.to_s, options, html_options) Chris@909: # end Chris@909: def pagination_links_each(paginator, options, prefix = nil, suffix = nil) Chris@909: options = DEFAULT_OPTIONS.merge(options) Chris@909: link_to_current_page = options[:link_to_current_page] Chris@909: always_show_anchors = options[:always_show_anchors] Chris@909: Chris@909: current_page = paginator.current_page Chris@909: window_pages = current_page.window(options[:window_size]).pages Chris@909: return if window_pages.length <= 1 unless link_to_current_page Chris@909: Chris@909: first, last = paginator.first, paginator.last Chris@909: Chris@909: html = '' Chris@909: Chris@909: html << prefix if prefix Chris@909: Chris@909: if always_show_anchors and not (wp_first = window_pages[0]).first? Chris@909: html << yield(first.number) Chris@909: html << ' ... ' if wp_first.number - first.number > 1 Chris@909: html << ' ' Chris@909: end Chris@909: Chris@909: window_pages.each do |page| Chris@909: if current_page == page && !link_to_current_page Chris@909: html << page.number.to_s Chris@909: else Chris@909: html << yield(page.number) Chris@909: end Chris@909: html << ' ' Chris@909: end Chris@909: Chris@909: if always_show_anchors and not (wp_last = window_pages[-1]).last? Chris@909: html << ' ... ' if last.number - wp_last.number > 1 Chris@909: html << yield(last.number) Chris@909: end Chris@909: Chris@909: html << suffix if suffix Chris@909: Chris@909: html Chris@909: end Chris@909: Chris@909: end # PaginationHelper Chris@909: end # Helpers Chris@909: end # ActionView