]> git.openstreetmap.org Git - rails.git/blob - lib/classic_pagination/pagination_helper.rb
Merge pull request #5295 from tomhughes/danger-branches
[rails.git] / lib / classic_pagination / pagination_helper.rb
1 module ActionView
2   module Helpers
3     # Provides methods for linking to ActionController::Pagination objects using a simple generator API.  You can optionally
4     # also build your links manually using ActionView::Helpers::AssetHelper#link_to like so:
5     #
6     # <%= link_to "Previous page", { :page => paginator.current.previous } if paginator.current.previous %>
7     # <%= link_to "Next page", { :page => paginator.current.next } if paginator.current.next %>
8     module PaginationHelper
9       unless const_defined?(:DEFAULT_OPTIONS)
10         DEFAULT_OPTIONS = {
11           :name => :page,
12           :window_size => 2,
13           :always_show_anchors => true,
14           :link_to_current_page => false,
15           :params => {}
16         }.freeze
17       end
18
19       # Creates a basic HTML link bar for the given +paginator+.  Links will be created
20       # for the next and/or previous page and for a number of other pages around the current
21       # pages position. The +html_options+ hash is passed to +link_to+ when the links are created.
22       #
23       # ==== Options
24       # <tt>:name</tt>::                 the routing name for this paginator
25       #                                  (defaults to +page+)
26       # <tt>:prefix</tt>::               prefix for pagination links
27       #                                  (i.e. Older Pages: 1 2 3 4)
28       # <tt>:suffix</tt>::               suffix for pagination links
29       #                                  (i.e. 1 2 3 4 <- Older Pages)
30       # <tt>:window_size</tt>::          the number of pages to show around
31       #                                  the current page (defaults to <tt>2</tt>)
32       # <tt>:always_show_anchors</tt>::  whether or not the first and last
33       #                                  pages should always be shown
34       #                                  (defaults to +true+)
35       # <tt>:link_to_current_page</tt>:: whether or not the current page
36       #                                  should be linked to (defaults to
37       #                                  +false+)
38       # <tt>:params</tt>::               any additional routing parameters
39       #                                  for page URLs
40       #
41       # ==== Examples
42       #  # We'll assume we have a paginator setup in @person_pages...
43       #
44       #  pagination_links(@person_pages)
45       #  # => 1 <a href="/?page=2/">2</a> <a href="/?page=3/">3</a>  ... <a href="/?page=10/">10</a>
46       #
47       #  pagination_links(@person_pages, :link_to_current_page => true)
48       #  # => <a href="/?page=1/">1</a> <a href="/?page=2/">2</a> <a href="/?page=3/">3</a>  ... <a href="/?page=10/">10</a>
49       #
50       #  pagination_links(@person_pages, :always_show_anchors => false)
51       #  # => 1 <a href="/?page=2/">2</a> <a href="/?page=3/">3</a>
52       #
53       #  pagination_links(@person_pages, :window_size => 1)
54       #  # => 1 <a href="/?page=2/">2</a>  ... <a href="/?page=10/">10</a>
55       #
56       #  pagination_links(@person_pages, :params => { :viewer => "flash" })
57       #  # => 1 <a href="/?page=2&amp;viewer=flash/">2</a> <a href="/?page=3&amp;viewer=flash/">3</a>  ...
58       #  #    <a href="/?page=10&amp;viewer=flash/">10</a>
59       def pagination_links(paginator, options = {}, html_options = {})
60         name = options[:name] || DEFAULT_OPTIONS[:name]
61         params = (options[:params] || DEFAULT_OPTIONS[:params]).clone
62
63         prefix = options[:prefix] || ""
64         suffix = options[:suffix] || ""
65
66         pagination_links_each(paginator, options, prefix, suffix) do |n|
67           params[name] = n
68           link_to(n.to_s, params, html_options)
69         end
70       end
71
72       # Iterate through the pages of a given +paginator+, invoking a
73       # block for each page number that needs to be rendered as a link.
74       #
75       # ==== Options
76       # <tt>:window_size</tt>::          the number of pages to show around
77       #                                  the current page (defaults to +2+)
78       # <tt>:always_show_anchors</tt>::  whether or not the first and last
79       #                                  pages should always be shown
80       #                                  (defaults to +true+)
81       # <tt>:link_to_current_page</tt>:: whether or not the current page
82       #                                  should be linked to (defaults to
83       #                                  +false+)
84       #
85       # ==== Example
86       #  # Turn paginated links into an Ajax call
87       #  pagination_links_each(paginator, page_options) do |link|
88       #    options = { :url => {:action => 'list'}, :update => 'results' }
89       #    html_options = { :href => url_for(:action => 'list') }
90       #
91       #    link_to_remote(link.to_s, options, html_options)
92       #  end
93       def pagination_links_each(paginator, options, prefix = nil, suffix = nil)
94         options = DEFAULT_OPTIONS.merge(options)
95         link_to_current_page = options[:link_to_current_page]
96         always_show_anchors = options[:always_show_anchors]
97
98         current_page = paginator.current_page
99         window_pages = current_page.window(options[:window_size]).pages
100         return unless link_to_current_page || window_pages.length > 1
101
102         first = paginator.first
103         last = paginator.last
104
105         html = ""
106
107         html << prefix if prefix
108
109         if always_show_anchors && !(wp_first = window_pages[0]).first?
110           html << yield(first.number)
111           html << " ... " if wp_first.number - first.number > 1
112           html << " "
113         end
114
115         window_pages.each do |page|
116           html << if current_page == page && !link_to_current_page
117                     page.number.to_s
118                   else
119                     yield(page.number)
120                   end
121           html << " "
122         end
123
124         if always_show_anchors && !(wp_last = window_pages[-1]).last?
125           html << " ... " if last.number - wp_last.number > 1
126           html << yield(last.number)
127         end
128
129         html << suffix if suffix
130
131         html
132       end
133
134       def pagination_items(paginator, options)
135         options = DEFAULT_OPTIONS.merge(options)
136         link_to_current_page = options[:link_to_current_page]
137         always_show_anchors = options[:always_show_anchors]
138
139         current_page = paginator.current_page
140         window_pages = current_page.window(options[:window_size]).pages
141
142         first = paginator.first
143         last = paginator.last
144
145         items = []
146
147         if always_show_anchors && !(wp_first = window_pages[0]).first?
148           items.push [first.number.to_s, first]
149           items.push ["...", "disabled"] if wp_first.number - first.number > 1
150         end
151
152         window_pages.each do |page|
153           if current_page == page && !link_to_current_page
154             items.push [page.number.to_s, "active"]
155           else
156             items.push [page.number.to_s, page]
157           end
158         end
159
160         if always_show_anchors && !(wp_last = window_pages[-1]).last?
161           items.push ["...", "disabled"] if last.number - wp_last.number > 1
162           items.push [last.number.to_s, last]
163         end
164
165         items
166       end
167     end
168   end
169 end