will_paginate 2.3.15 → 2.3.16

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of will_paginate might be problematic. Click here for more details.

data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,25 @@
1
+ = 2.3.16, released 2011-08-09
2
+
3
+ * added global <tt>WillPaginate.per_page = 30</tt> setting
4
+ * added i18n capabilities to previous/next labels and page_entries_info
5
+ * page_entries_info ":entry_name" parameter is now renamed to ":model"
6
+ * new option: page_entries_info(:html => false)
7
+ * fix page_entries_info output with rails_xss
8
+ * raise an InvalidPage exception if the calculated offset is bigger than BIGINT
9
+ * fixed bugs with Rails 1.2.6
10
+
11
+ = 2.3.15, released 2010-09-09
12
+
13
+ * ensure respond_to? works as expected considering methods that begin with 'paginate'
14
+ * fix counting in pagination when Integer has length method (Ruby Facets)
15
+ * stop using deprecated Object#returning
16
+ * fixed has_many :through in combination with `:uniq` for Postgres and SQLite3
17
+
18
+ = 2.3.14, released 2010-05-26
19
+ = 2.3.13, released 2010-05-26
20
+
21
+ * better rails_xss compatibility
22
+
1
23
  = 2.3.12, released 2009-12-01
2
24
 
3
25
  * make view helpers "HTML safe" for Rails 2.3.5 with rails_xss plugin
data/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # will_paginate
2
+
3
+ will_paginate v2.3 is a pagination plugin for Rails and Active Record.
4
+
5
+ Installation:
6
+
7
+ ~~~ ruby
8
+ ## environment.rb
9
+ Rails::Initializer.run do |config|
10
+ config.gem 'will_paginate', :version => '~> 2.3.16'
11
+ end
12
+ ~~~
13
+
14
+ See [installation instructions][install] on the wiki for more info.
15
+
16
+
17
+ ## Basic will_paginate use
18
+
19
+ ~~~ ruby
20
+ ## perform a paginated query:
21
+ @posts = Post.paginate(:page => params[:page])
22
+
23
+ # or, use an explicit "per page" limit:
24
+ Post.paginate(:page => params[:page], :per_page => 30)
25
+
26
+ ## render page links in the view:
27
+ <%= will_paginate @posts %>
28
+ ~~~
29
+
30
+ And that's it! You're done. You just need to add some CSS styles to [make those pagination links prettier][css].
31
+
32
+ You can customize the default "per_page" value:
33
+
34
+ ~~~ ruby
35
+ # for the Post model
36
+ class Post
37
+ self.per_page = 10
38
+ end
39
+
40
+ # set per_page globally
41
+ WillPaginate.per_page = 10
42
+ ~~~
43
+
44
+ See [the wiki][wiki] for more documentation. [Ask on the group][group] if you have usage questions. [Report bugs][issues] on GitHub.
45
+
46
+ Happy paginating.
47
+
48
+
49
+ [wiki]: https://github.com/mislav/will_paginate/wiki
50
+ [install]: https://github.com/mislav/will_paginate/wiki/Installation "will_paginate installation"
51
+ [group]: http://groups.google.com/group/will_paginate "will_paginate discussion and support group"
52
+ [issues]: https://github.com/mislav/will_paginate/issues
53
+ [css]: http://mislav.uniqpath.com/will_paginate/
data/Rakefile CHANGED
@@ -1,53 +1,28 @@
1
- require 'rubygems'
2
- begin
3
- hanna_dir = '/Users/mislav/Projects/Hanna/lib'
4
- $:.unshift hanna_dir if File.exists? hanna_dir
5
- require 'hanna/rdoctask'
6
- rescue LoadError
7
- require 'rake'
8
- require 'rake/rdoctask'
9
- end
10
- load 'test/tasks.rake'
1
+ require 'rake/testtask'
11
2
 
12
3
  desc 'Default: run unit tests.'
13
4
  task :default => :test
14
5
 
15
- desc 'Generate RDoc documentation for the will_paginate plugin.'
16
- Rake::RDocTask.new(:rdoc) do |rdoc|
17
- rdoc.rdoc_files.include('README.rdoc', 'LICENSE', 'CHANGELOG.rdoc').
18
- include('lib/**/*.rb').
19
- exclude('lib/will_paginate/named_scope*').
20
- exclude('lib/will_paginate/array.rb').
21
- exclude('lib/will_paginate/version.rb')
22
-
23
- rdoc.main = "README.rdoc" # page to start on
24
- rdoc.title = "will_paginate documentation"
25
-
26
- rdoc.rdoc_dir = 'doc' # rdoc output folder
27
- rdoc.options << '--inline-source' << '--charset=UTF-8'
28
- rdoc.options << '--webcvs=http://github.com/mislav/will_paginate/tree/master/'
6
+ desc 'Test the will_paginate plugin.'
7
+ Rake::TestTask.new(:test) do |t|
8
+ if ENV['DB'] and ENV['DB'] != 'sqlite3'
9
+ t.pattern = %w[test/finder_test.rb]
10
+ else
11
+ t.pattern = 'test/**/*_test.rb'
12
+ end
13
+ t.libs << 'test'
29
14
  end
30
15
 
31
- desc %{Update ".manifest" with the latest list of project filenames. Respect\
32
- .gitignore by excluding everything that git ignores. Update `files` and\
33
- `test_files` arrays in "*.gemspec" file if it's present.}
34
- task :manifest do
35
- list = `git ls-files --full-name --exclude=*.gemspec --exclude=.*`.chomp.split("\n")
36
-
37
- if spec_file = Dir['*.gemspec'].first
38
- spec = File.read spec_file
39
- spec.gsub! /^(\s* s.(test_)?files \s* = \s* )( \[ [^\]]* \] | %w\( [^)]* \) )/mx do
40
- assignment = $1
41
- bunch = $2 ? list.grep(/^test\//) : list
42
- '%s%%w(%s)' % [assignment, bunch.join(' ')]
43
- end
44
-
45
- File.open(spec_file, 'w') { |f| f << spec }
16
+ namespace :test do ||
17
+ desc 'Test only Rails integration'
18
+ Rake::TestTask.new(:rails) do |t|
19
+ t.pattern = %w[test/finder_test.rb test/view_test.rb]
20
+ t.libs << 'test'
46
21
  end
47
- File.open('.manifest', 'w') { |f| f << list.join("\n") }
48
- end
49
22
 
50
- task :examples do
51
- %x(haml examples/index.haml examples/index.html)
52
- %x(sass examples/pagination.sass examples/pagination.css)
23
+ desc 'Test only ActiveRecord integration'
24
+ Rake::TestTask.new(:db) do |t|
25
+ t.pattern = %w[test/finder_test.rb]
26
+ t.libs << 'test'
27
+ end
53
28
  end
data/lib/will_paginate.rb CHANGED
@@ -36,12 +36,13 @@ module WillPaginate
36
36
 
37
37
  # support pagination on associations
38
38
  a = ActiveRecord::Associations
39
- [ a::AssociationCollection ].tap { |classes|
40
- # detect http://dev.rubyonrails.org/changeset/9230
41
- unless a::HasManyThroughAssociation.superclass == a::HasManyAssociation
42
- classes << a::HasManyThroughAssociation
43
- end
44
- }.each do |klass|
39
+ klasses = [ a::AssociationCollection ]
40
+ # detect http://dev.rubyonrails.org/changeset/9230
41
+ unless a::HasManyThroughAssociation.superclass == a::HasManyAssociation
42
+ klasses << a::HasManyThroughAssociation
43
+ end
44
+
45
+ klasses.each do |klass|
45
46
  klass.send :include, Finder::ClassMethods
46
47
  klass.class_eval { alias_method_chain :method_missing, :paginate }
47
48
  end
@@ -88,3 +89,9 @@ if defined? Rails
88
89
  WillPaginate.enable_activerecord if defined? ActiveRecord
89
90
  WillPaginate.enable_actionpack if defined? ActionController
90
91
  end
92
+
93
+ # load default translations only for newer versions of I18n
94
+ if defined? I18n and not defined? I18n::Backend::Simple::MATCH
95
+ require 'will_paginate/i18n'
96
+ I18n.load_path.unshift(*WillPaginate::I18n.load_path)
97
+ end
@@ -1,16 +1,16 @@
1
1
  require 'will_paginate/collection'
2
+ require 'will_paginate/per_page'
2
3
 
3
4
  # http://www.desimcadam.com/archives/8
4
5
  Array.class_eval do
5
6
  def paginate(options = {})
6
7
  raise ArgumentError, "parameter hash expected (got #{options.inspect})" unless Hash === options
7
-
8
- WillPaginate::Collection.create(
9
- options[:page] || 1,
10
- options[:per_page] || 30,
11
- options[:total_entries] || self.length
12
- ) { |pager|
8
+ page = options[:page] || 1
9
+ per_page = options[:per_page] || WillPaginate.per_page
10
+ total = options[:total_entries] || self.length
11
+
12
+ WillPaginate::Collection.create(page, per_page, total) do |pager|
13
13
  pager.replace self[pager.offset, pager.per_page].to_a
14
- }
14
+ end
15
15
  end
16
16
  end
@@ -1,3 +1,5 @@
1
+ require 'will_paginate/per_page'
2
+
1
3
  module WillPaginate
2
4
  # = Invalid page number error
3
5
  # This is an ArgumentError raised in case a page was requested that is either
@@ -17,8 +19,24 @@ module WillPaginate
17
19
  # requested. Use <tt>WillPaginate::Collection#out_of_bounds?</tt> method to
18
20
  # check for those cases and manually deal with them as you see fit.
19
21
  class InvalidPage < ArgumentError
20
- def initialize(page, page_num)
21
- super "#{page.inspect} given as value, which translates to '#{page_num}' as page number"
22
+ # a value bigger than this would result in invalid SQL queries
23
+ BIGINT = 9223372036854775807
24
+
25
+ def self.validate(page_value, per_page_value)
26
+ page = page_value.to_i
27
+ raise self.new(page_value, page) if page < 1
28
+ per_page = per_page_value.to_i
29
+ offset = (page - 1) * per_page
30
+ raise self, "invalid offset: #{offset.inspect}" if offset < 0 or offset > BIGINT
31
+ [page, per_page]
32
+ end
33
+
34
+ def initialize(value, page_num = nil)
35
+ if page_num
36
+ super "#{value.inspect} given as value, which translates to '#{page_num}' as page number"
37
+ else
38
+ super value
39
+ end
22
40
  end
23
41
  end
24
42
 
@@ -44,12 +62,8 @@ module WillPaginate
44
62
  # and the total number of entries. The last argument is optional because it
45
63
  # is best to do lazy counting; in other words, count *conditionally* after
46
64
  # populating the collection using the +replace+ method.
47
- def initialize(page, per_page, total = nil)
48
- @current_page = page.to_i
49
- raise InvalidPage.new(page, @current_page) if @current_page < 1
50
- @per_page = per_page.to_i
51
- raise ArgumentError, "`per_page` setting cannot be less than 1 (#{@per_page} given)" if @per_page < 1
52
-
65
+ def initialize(page, per_page = WillPaginate.per_page, total = nil)
66
+ @current_page, @per_page = InvalidPage.validate(page, per_page)
53
67
  self.total_entries = total if total
54
68
  end
55
69
 
@@ -1,4 +1,5 @@
1
1
  require 'will_paginate/core_ext'
2
+ require 'will_paginate/per_page'
2
3
 
3
4
  module WillPaginate
4
5
  # A mixin for ActiveRecord::Base. Provides +per_page+ class method
@@ -8,11 +9,10 @@ module WillPaginate
8
9
  #
9
10
  module Finder
10
11
  def self.included(base)
12
+ base.extend PerPage
11
13
  base.extend ClassMethods
12
14
  class << base
13
15
  alias_method_chain :method_missing, :paginate
14
- # alias_method_chain :find_every, :paginate
15
- define_method(:per_page) { 30 } unless respond_to?(:per_page)
16
16
  end
17
17
  end
18
18
 
@@ -0,0 +1,29 @@
1
+ module WillPaginate
2
+ module I18n
3
+ def self.locale_dir
4
+ File.expand_path('../locale', __FILE__)
5
+ end
6
+
7
+ def self.load_path
8
+ Dir["#{locale_dir}/*.{rb,yml}"]
9
+ end
10
+
11
+ def will_paginate_translate(keys, options = {})
12
+ if defined? ::I18n
13
+ defaults = Array(keys).dup
14
+ if block_given?
15
+ if defined? ::I18n::Backend::Simple::MATCH
16
+ # procs in defaults array were not supported back then
17
+ defaults << yield(defaults.first, options)
18
+ else
19
+ defaults << Proc.new
20
+ end
21
+ end
22
+ ::I18n.translate(defaults.shift, options.merge(:default => defaults, :scope => :will_paginate))
23
+ else
24
+ key = Array === keys ? keys.first : keys
25
+ yield key, options
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ en:
2
+ will_paginate:
3
+ previous_label: "&laquo; Previous"
4
+ next_label: "Next &raquo;"
5
+ page_gap: "&hellip;"
6
+
7
+ page_entries_info:
8
+ single_page:
9
+ zero: "No %{model} found"
10
+ one: "Displaying 1 %{model}"
11
+ other: "Displaying all %{count} %{model}"
12
+ single_page_html:
13
+ zero: "No %{model} found"
14
+ one: "Displaying <b>1</b> %{model}"
15
+ other: "Displaying <b>all&nbsp;%{count}</b> %{model}"
16
+
17
+ multi_page: "Displaying %{model} %{from} - %{to} of %{count} in total"
18
+ multi_page_html: "Displaying %{model} <b>%{from}&nbsp;-&nbsp;%{to}</b> of <b>%{count}</b> in total"
19
+
20
+ # models:
21
+ # entry:
22
+ # zero: entries
23
+ # one: entry
24
+ # few: entries
25
+ # other: entries
26
+
27
+ # line_item:
28
+ # page_entries_info:
29
+ # single_page:
30
+ # zero: "Your shopping cart is empty"
31
+ # one: "Displaying one item in your cart"
32
+ # other: "Displaying all %{count} items"
33
+ # multi_page: "Displaying items %{from} - %{to} of %{count} in total"
@@ -0,0 +1,27 @@
1
+ module WillPaginate
2
+ module PerPage
3
+ def per_page
4
+ defined?(@per_page) ? @per_page : WillPaginate.per_page
5
+ end
6
+
7
+ def per_page=(limit)
8
+ @per_page = limit.to_i
9
+ end
10
+
11
+ def self.extended(base)
12
+ base.extend Inheritance if base.is_a? Class
13
+ end
14
+
15
+ module Inheritance
16
+ def inherited(subclass)
17
+ super
18
+ subclass.per_page = self.per_page
19
+ end
20
+ end
21
+ end
22
+
23
+ extend PerPage
24
+
25
+ # default number of items per page
26
+ self.per_page = 30
27
+ end
@@ -2,7 +2,7 @@ module WillPaginate
2
2
  module VERSION
3
3
  MAJOR = 2
4
4
  MINOR = 3
5
- TINY = 15
5
+ TINY = 16
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -1,4 +1,5 @@
1
1
  require 'will_paginate/core_ext'
2
+ require 'will_paginate/i18n'
2
3
 
3
4
  module WillPaginate
4
5
  # = Will Paginate view helpers
@@ -20,11 +21,13 @@ module WillPaginate
20
21
  # older versions of Rails) you can easily translate link texts to previous
21
22
  # and next pages, as well as override some other defaults to your liking.
22
23
  module ViewHelpers
24
+ include WillPaginate::I18n
25
+
23
26
  # default options that can be overridden on the global level
24
27
  @@pagination_options = {
25
28
  :class => 'pagination',
26
- :previous_label => '&laquo; Previous',
27
- :next_label => 'Next &raquo;',
29
+ :previous_label => nil,
30
+ :next_label => nil,
28
31
  :inner_window => 4, # links around the current page
29
32
  :outer_window => 1, # links around beginning and end
30
33
  :separator => ' ', # single space is friendly to spiders and non-graphic browsers
@@ -102,7 +105,10 @@ module WillPaginate
102
105
  WillPaginate::Deprecation::warn(":prev_label view parameter is now :previous_label; the old name has been deprecated", caller)
103
106
  options[:previous_label] = options.delete(:prev_label)
104
107
  end
105
-
108
+
109
+ options[:previous_label] ||= will_paginate_translate(:previous_label) { '&laquo; Previous' }
110
+ options[:next_label] ||= will_paginate_translate(:next_label) { 'Next &raquo;' }
111
+
106
112
  # get the renderer instance
107
113
  renderer = case options[:renderer]
108
114
  when String
@@ -142,7 +148,7 @@ module WillPaginate
142
148
  def paginated_section(*args, &block)
143
149
  pagination = will_paginate(*args).to_s
144
150
 
145
- unless ActionView::Base.respond_to? :erb_variable
151
+ if respond_to? :output_buffer
146
152
  concat pagination
147
153
  yield
148
154
  concat pagination
@@ -160,31 +166,64 @@ module WillPaginate
160
166
  #
161
167
  # By default, the message will use the humanized class name of objects
162
168
  # in collection: for instance, "project types" for ProjectType models.
163
- # Override this with the <tt>:entry_name</tt> parameter:
169
+ # Override this with the <tt>:model</tt> parameter:
164
170
  #
165
- # <%= page_entries_info @posts, :entry_name => 'item' %>
171
+ # <%= page_entries_info @posts, :model => 'item' %>
166
172
  # #-> Displaying items 6 - 10 of 26 in total
167
173
  def page_entries_info(collection, options = {})
168
- entry_name = options[:entry_name] ||
169
- (collection.empty?? 'entry' : collection.first.class.name.underscore.sub('_', ' '))
170
-
171
- if collection.total_pages < 2
172
- case collection.size
173
- when 0; "No #{entry_name.pluralize} found"
174
- when 1; "Displaying <b>1</b> #{entry_name}"
175
- else; "Displaying <b>all #{collection.size}</b> #{entry_name.pluralize}"
174
+ if options.key? :entry_name
175
+ WillPaginate::Deprecation::warn(":entry_name parameter is now called :model", caller)
176
+ end
177
+ model = options[:model] || options[:entry_name]
178
+ model = collection.first.class unless model or collection.empty?
179
+ model ||= 'entry'
180
+
181
+ if html = options.fetch(:html, true)
182
+ b, eb = '<b>', '</b>'
183
+ sp = '&nbsp;'
184
+ html_key = '_html'
185
+ else
186
+ b = eb = html_key = ''
187
+ sp = ' '
188
+ end
189
+
190
+ model_key = model.to_s.underscore
191
+ model_count = collection.total_pages > 1 ? 5 : collection.size
192
+ model_name = will_paginate_translate "models.#{model_key}", :count => model_count do |_, opts|
193
+ name = model_key.to_s.tr('_/', ' ')
194
+ raise "can't pluralize model name: #{model.inspect}" unless name.respond_to? :pluralize
195
+ opts[:count] == 1 ? name : name.pluralize
196
+ end
197
+
198
+ output = if collection.total_pages < 2
199
+ i18n_key = :"page_entries_info.single_page#{html_key}"
200
+ keys = [:"#{model_key}.#{i18n_key}", i18n_key]
201
+
202
+ will_paginate_translate keys, :count => collection.size, :model => model_name do |_, opts|
203
+ case opts[:count]
204
+ when 0; "No #{opts[:model]} found"
205
+ when 1; "Displaying #{b}1#{eb} #{opts[:model]}"
206
+ else "Displaying #{b}all#{sp}#{opts[:count]}#{eb} #{opts[:model]}"
207
+ end
176
208
  end
177
209
  else
178
- %{Displaying #{entry_name.pluralize} <b>%d&nbsp;-&nbsp;%d</b> of <b>%d</b> in total} % [
179
- collection.offset + 1,
180
- collection.offset + collection.length,
181
- collection.total_entries
182
- ]
210
+ i18n_key = :"page_entries_info.multi_page#{html_key}"
211
+ keys = [:"#{model_key}.#{i18n_key}", i18n_key]
212
+ params = {
213
+ :model => model_name, :count => collection.total_entries,
214
+ :from => collection.offset + 1, :to => collection.offset + collection.length
215
+ }
216
+ will_paginate_translate keys, params do |_, opts|
217
+ %{Displaying %s #{b}%d#{sp}-#{sp}%d#{eb} of #{b}%d#{eb} in total} %
218
+ [ opts[:model], opts[:from], opts[:to], opts[:count] ]
219
+ end
220
+ end
221
+
222
+ if html and output.respond_to?(:html_safe)
223
+ output.html_safe
224
+ else
225
+ output
183
226
  end
184
- end
185
-
186
- if respond_to? :safe_helper
187
- safe_helper :will_paginate, :paginated_section, :page_entries_info
188
227
  end
189
228
 
190
229
  def self.total_pages_for_collection(collection) #:nodoc:
@@ -205,15 +244,6 @@ module WillPaginate
205
244
  # This class does the heavy lifting of actually building the pagination
206
245
  # links. It is used by the <tt>will_paginate</tt> helper internally.
207
246
  class LinkRenderer
208
-
209
- # The gap in page links is represented by:
210
- #
211
- # <span class="gap">&hellip;</span>
212
- attr_accessor :gap_marker
213
-
214
- def initialize
215
- @gap_marker = '<span class="gap">&hellip;</span>'
216
- end
217
247
 
218
248
  # * +collection+ is a WillPaginate::Collection instance or any other object
219
249
  # that conforms to that API
@@ -253,6 +283,18 @@ module WillPaginate
253
283
  end
254
284
  @html_attributes
255
285
  end
286
+
287
+ attr_writer :gap_marker
288
+
289
+ # The gap in page links is represented by:
290
+ #
291
+ # <span class="gap">&hellip;</span>
292
+ def gap_marker
293
+ @gap_marker ||= begin
294
+ gap_text = @template.will_paginate_translate(:page_gap) { '&hellip;' }
295
+ %(<span class="gap">#{gap_text}</span>)
296
+ end
297
+ end
256
298
 
257
299
  protected
258
300
 
@@ -395,7 +437,8 @@ module WillPaginate
395
437
  if defined? Rack::Utils
396
438
  # For Rails > 2.3
397
439
  Rack::Utils.parse_nested_query(params)
398
- elsif defined?(ActionController::AbstractRequest)
440
+ elsif defined?(ActionController::AbstractRequest) and
441
+ ActionController::AbstractRequest.respond_to? :parse_query_parameters
399
442
  ActionController::AbstractRequest.parse_query_parameters(params)
400
443
  elsif defined?(ActionController::UrlEncodedPairParser)
401
444
  # For Rails > 2.2