folio-pagination-legacy 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.travis.yml +3 -0
- data/Gemfile +16 -0
- data/Guardfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +235 -0
- data/Rakefile +11 -0
- data/folio-pagination-legacy.gemspec +30 -0
- data/lib/folio-pagination-legacy.rb +3 -0
- data/lib/folio.rb +84 -0
- data/lib/folio/core_ext/enumerable.rb +51 -0
- data/lib/folio/invalid_page.rb +5 -0
- data/lib/folio/ordinal.rb +33 -0
- data/lib/folio/ordinal/page.rb +107 -0
- data/lib/folio/page.rb +86 -0
- data/lib/folio/per_page.rb +15 -0
- data/lib/folio/rails.rb +21 -0
- data/lib/folio/version.rb +3 -0
- data/lib/folio/will_paginate/active_record.rb +71 -0
- data/lib/folio/will_paginate/array.rb +10 -0
- data/lib/folio/will_paginate/collection.rb +19 -0
- data/lib/folio/will_paginate/view_helpers.rb +59 -0
- data/lib/folio/will_paginate/view_helpers/action_view.rb +10 -0
- data/lib/folio/will_paginate/view_helpers/link_renderer.rb +53 -0
- data/test/folio/core_ext/enumerable_test.rb +55 -0
- data/test/folio/ordinal/page_test.rb +173 -0
- data/test/folio/ordinal_test.rb +57 -0
- data/test/folio/page_test.rb +198 -0
- data/test/folio/per_page_test.rb +49 -0
- data/test/folio/rails_test.rb +11 -0
- data/test/folio/version_test.rb +8 -0
- data/test/folio/will_paginate/active_record_test.rb +113 -0
- data/test/folio/will_paginate/collection_test.rb +43 -0
- data/test/folio/will_paginate/view_helpers/link_renderer_test.rb +160 -0
- data/test/folio/will_paginate/view_helpers_test.rb +49 -0
- data/test/folio_test.rb +192 -0
- data/test/setup/active_record.rb +13 -0
- metadata +133 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'folio'
|
2
|
+
require 'folio/ordinal/page'
|
3
|
+
require 'folio/invalid_page'
|
4
|
+
|
5
|
+
# Mix in to a source to provide the same methods as Folio, but with simpler
|
6
|
+
# build_page and fill_page methods required on the host (some responsibility is
|
7
|
+
# moved into the paginate method).
|
8
|
+
#
|
9
|
+
# * build_page no longer needs to configure ordinal_page?, first_page,
|
10
|
+
# or last_page on the instantiated page. Instead, just instantiate
|
11
|
+
# and return a Folio::Ordinal::Page. If what you return is not a
|
12
|
+
# Folio::Ordinal::Page, paginate will decorate it to be one.
|
13
|
+
#
|
14
|
+
# * fill_page no longer needs to configure next_page and previous_page; the
|
15
|
+
# ordinal page will handle them. (Note that if necessary, you can still set
|
16
|
+
# next_page explicitly to nil.) Also, paginate will now perform ordinal
|
17
|
+
# bounds checking for you, so you can focus entirely on populating the page.
|
18
|
+
#
|
19
|
+
module Folio
|
20
|
+
module Ordinal
|
21
|
+
# decorate the page before configuring, and then validate the configured
|
22
|
+
# current_page before returning it
|
23
|
+
def configure_pagination(page, options)
|
24
|
+
page = super(::Folio::Ordinal::Page.decorate(page), options)
|
25
|
+
raise ::Folio::InvalidPage unless page.current_page.is_a?(Integer)
|
26
|
+
raise ::Folio::InvalidPage if page.out_of_bounds?
|
27
|
+
page
|
28
|
+
end
|
29
|
+
|
30
|
+
# otherwise acts like a normal folio
|
31
|
+
include ::Folio
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'folio/page'
|
2
|
+
|
3
|
+
# Mix in to an Enumerable to provide the same methods as Folio::Page but with
|
4
|
+
# the following overrides:
|
5
|
+
#
|
6
|
+
# * ordinal_pages is always true
|
7
|
+
#
|
8
|
+
# * first_page is always 1
|
9
|
+
#
|
10
|
+
# * current_page is forced to an integer
|
11
|
+
#
|
12
|
+
# * previous_page is always either current_page-1 or nil, depending on how
|
13
|
+
# current_page relates to first_page.
|
14
|
+
#
|
15
|
+
# * next_page can only be set if total_pages is unknown. if total_pages is
|
16
|
+
# known, next_page will be either current_page+1 or nil, depending on how
|
17
|
+
# current_page relates to last_page. if total_pages is unknown and next_page
|
18
|
+
# is unset (vs. explicitly set to nil), it will default to current_page+1.
|
19
|
+
# if next_page is set to a non-nil value, that value will be forced to an
|
20
|
+
# integer.
|
21
|
+
#
|
22
|
+
# * last_page is deterministic: always total_pages if total_pages is known,
|
23
|
+
# current_page if total_pages is unknown and next_page is nil, nil otherwise
|
24
|
+
# (indicating the page sequence continues until next_page is nil).
|
25
|
+
module Folio
|
26
|
+
module Ordinal
|
27
|
+
module Page
|
28
|
+
def ordinal_pages
|
29
|
+
true
|
30
|
+
end
|
31
|
+
alias :ordinal_pages? :ordinal_pages
|
32
|
+
|
33
|
+
def first_page
|
34
|
+
1
|
35
|
+
end
|
36
|
+
|
37
|
+
def last_page
|
38
|
+
(total_pages || next_page) ? total_pages : current_page
|
39
|
+
end
|
40
|
+
|
41
|
+
def current_page=(value)
|
42
|
+
@current_page = value.to_i
|
43
|
+
end
|
44
|
+
|
45
|
+
def next_page=(value)
|
46
|
+
@next_page = value && value.to_i
|
47
|
+
end
|
48
|
+
|
49
|
+
def next_page
|
50
|
+
if total_pages && current_page >= total_pages
|
51
|
+
# known number of pages and we've reached the last one. no next page
|
52
|
+
# (even if explicitly set)
|
53
|
+
nil
|
54
|
+
elsif total_pages || !defined?(@next_page)
|
55
|
+
# (1) known number of pages and we haven't reached the last one
|
56
|
+
# (because we're not in the branch above), or
|
57
|
+
# (2) unknown number of pages, but nothing set, so we assume an
|
58
|
+
# infinite stream
|
59
|
+
# so there's a next page, and it's the one after this one
|
60
|
+
current_page + 1
|
61
|
+
else
|
62
|
+
# just use what they set
|
63
|
+
@next_page
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def previous_page
|
68
|
+
current_page > first_page ? current_page - 1 : nil
|
69
|
+
end
|
70
|
+
|
71
|
+
def out_of_bounds?
|
72
|
+
(current_page < first_page) || (last_page && current_page > last_page) || false
|
73
|
+
end
|
74
|
+
|
75
|
+
def offset
|
76
|
+
(current_page - 1) * per_page
|
77
|
+
end
|
78
|
+
|
79
|
+
class Decorator < Folio::Page::Decorator
|
80
|
+
include Folio::Ordinal::Page
|
81
|
+
end
|
82
|
+
|
83
|
+
class DecoratedArray < Decorator
|
84
|
+
def initialize
|
85
|
+
super []
|
86
|
+
end
|
87
|
+
|
88
|
+
def replace(array)
|
89
|
+
result = super
|
90
|
+
if total_entries.nil? and length < per_page and (current_page == 1 or length > 0)
|
91
|
+
self.total_entries = offset + length
|
92
|
+
end
|
93
|
+
result
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.decorate(collection)
|
98
|
+
collection = Folio::Ordinal::Page::Decorator.new(collection) unless collection.is_a?(Folio::Ordinal::Page)
|
99
|
+
collection
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.create
|
103
|
+
Folio::Ordinal::Page::DecoratedArray.new
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/lib/folio/page.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'folio/per_page'
|
2
|
+
require 'delegate'
|
3
|
+
|
4
|
+
# Mix into any Enumerable. The mixin gives you the eight attributes and
|
5
|
+
# one method described below.
|
6
|
+
#
|
7
|
+
# ordinal_pages?, first_page, and last_page are common to all pages
|
8
|
+
# created by a folio and are configured, as available, when the folio
|
9
|
+
# creates a blank page.
|
10
|
+
#
|
11
|
+
# current_page, per_page, and total_entries control the filling of a
|
12
|
+
# page and are configured from parameters to the folio's paginate
|
13
|
+
# method.
|
14
|
+
#
|
15
|
+
# next_page and previous_page are configured, as available, when the
|
16
|
+
# folio fills the configured page.
|
17
|
+
module Folio
|
18
|
+
module Page
|
19
|
+
# indicates whether the page identifiers in current_page,
|
20
|
+
# first_page, last_page, previous_page, and next_page should be
|
21
|
+
# considered ordinal or not.
|
22
|
+
attr_accessor :ordinal_pages
|
23
|
+
alias :ordinal_pages? :ordinal_pages
|
24
|
+
|
25
|
+
# page identifier addressing this page within the folio.
|
26
|
+
attr_accessor :current_page
|
27
|
+
|
28
|
+
# number of items requested from the folio when filling the page.
|
29
|
+
include Folio::PerPage
|
30
|
+
|
31
|
+
# page identifier addressing the first page within the folio.
|
32
|
+
attr_accessor :first_page
|
33
|
+
|
34
|
+
# page identifier addressing the final page within the folio, if
|
35
|
+
# known.
|
36
|
+
def last_page=(value)
|
37
|
+
@last_page = value
|
38
|
+
end
|
39
|
+
|
40
|
+
def last_page
|
41
|
+
if next_page.nil?
|
42
|
+
current_page
|
43
|
+
else
|
44
|
+
@last_page
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# page identifier addressing the immediately following page within
|
49
|
+
# the folio, if there is one.
|
50
|
+
attr_accessor :next_page
|
51
|
+
|
52
|
+
# page identifier addressing the immediately preceding page within
|
53
|
+
# the folio, if there is one and it is known.
|
54
|
+
attr_accessor :previous_page
|
55
|
+
|
56
|
+
# number of items in the folio, if known.
|
57
|
+
attr_accessor :total_entries
|
58
|
+
|
59
|
+
# number of pages in the folio, if known. calculated from
|
60
|
+
# total_entries and per_page.
|
61
|
+
def total_pages
|
62
|
+
return nil unless total_entries && per_page && per_page > 0
|
63
|
+
return 1 if total_entries <= 0
|
64
|
+
(total_entries / per_page.to_f).ceil
|
65
|
+
end
|
66
|
+
|
67
|
+
class Decorator < ::SimpleDelegator
|
68
|
+
include Folio::Page
|
69
|
+
end
|
70
|
+
|
71
|
+
class DecoratedArray < Decorator
|
72
|
+
def initialize
|
73
|
+
super []
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.decorate(collection)
|
78
|
+
collection = Folio::Page::Decorator.new(collection) unless collection.is_a?(Folio::Page)
|
79
|
+
collection
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.create
|
83
|
+
Folio::Page::DecoratedArray.new
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Folio
|
2
|
+
module PerPage
|
3
|
+
def default_per_page
|
4
|
+
Folio.per_page
|
5
|
+
end
|
6
|
+
|
7
|
+
def per_page(*args)
|
8
|
+
raise ArgumentError if args.size > 1
|
9
|
+
@per_page = (args.first && args.first.to_i) if args.size > 0
|
10
|
+
@per_page ? @per_page : default_per_page
|
11
|
+
end
|
12
|
+
|
13
|
+
alias_method :per_page=, :per_page
|
14
|
+
end
|
15
|
+
end
|
data/lib/folio/rails.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
begin
|
2
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
3
|
+
require 'action_controller'
|
4
|
+
rescue LoadError
|
5
|
+
raise "folio-pagination-legacy's rails support requires rails"
|
6
|
+
end
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'will_paginate/view_helpers'
|
10
|
+
rescue LoadError
|
11
|
+
raise "folio-pagination-legacy's rails support requires will_paginate"
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'folio/will_paginate/view_helpers'
|
15
|
+
|
16
|
+
ActionView::Base.send :include, WillPaginate::ViewHelpers
|
17
|
+
if defined?(ActionController::Base) and ActionController::Base.respond_to? :rescue_responses
|
18
|
+
ActionController::Base.rescue_responses['Folio::InvalidPage'] = :not_found
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'folio/will_paginate/active_record'
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# place WillPaginate's versions in place first to ensure the folio versions
|
2
|
+
# included later are used
|
3
|
+
begin
|
4
|
+
require 'active_record'
|
5
|
+
rescue LoadError
|
6
|
+
raise "folio-pagination-legacy's activerecord support requires activerecord"
|
7
|
+
end
|
8
|
+
|
9
|
+
begin
|
10
|
+
require 'will_paginate/finder'
|
11
|
+
rescue LoadError
|
12
|
+
raise "folio-pagination-legacy's activerecord support requires will_paginate"
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveRecord::Base.send :include, WillPaginate::Finder
|
16
|
+
ActiveRecord::Associations::AssociationCollection.send :include, WillPaginate::Finder::ClassMethods
|
17
|
+
|
18
|
+
require 'folio/ordinal'
|
19
|
+
require 'folio/ordinal/page'
|
20
|
+
require 'folio/will_paginate/array'
|
21
|
+
|
22
|
+
module Folio
|
23
|
+
module WillPaginate
|
24
|
+
# replaces model_or_association.paginate(...) method to behave like that
|
25
|
+
# from Folio while preserving basic mechanics of the version from
|
26
|
+
# WillPaginate.
|
27
|
+
#
|
28
|
+
# differences:
|
29
|
+
#
|
30
|
+
# * paginate does *not* recognize any parameters beyond those described in
|
31
|
+
# for Folio's paginate (e.g. finder options, count options).
|
32
|
+
#
|
33
|
+
module ActiveRecord
|
34
|
+
module Pagination
|
35
|
+
include Folio::Ordinal
|
36
|
+
|
37
|
+
def paginate_with_wp_count(options={})
|
38
|
+
unless options.has_key?(:total_entries)
|
39
|
+
page = (options.fetch(:page) { 1 }).to_i
|
40
|
+
per_page = (options.fetch(:per_page) { self.per_page }).to_i
|
41
|
+
offset = (page - 1) * per_page
|
42
|
+
options[:total_entries] = wp_count({}, [:all, {offset: offset, limit: per_page}], 'find')
|
43
|
+
end
|
44
|
+
paginate_without_wp_count(options)
|
45
|
+
end
|
46
|
+
alias_method_chain :paginate, :wp_count
|
47
|
+
|
48
|
+
def build_page
|
49
|
+
Folio::Ordinal::Page.create
|
50
|
+
end
|
51
|
+
|
52
|
+
# load the results and place them in the page
|
53
|
+
def fill_page(page)
|
54
|
+
page.replace self.find(:all, offset: page.offset, limit: page.per_page)
|
55
|
+
page
|
56
|
+
end
|
57
|
+
|
58
|
+
# don't try and look at Class (ActiveRecord::Base.class, etc.) for
|
59
|
+
# defaults
|
60
|
+
def default_per_page
|
61
|
+
Folio.per_page
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# mix into Active Record. these are the same ones that WillPaginate mixes
|
66
|
+
# its version of pagination into.
|
67
|
+
::ActiveRecord::Base.extend Pagination
|
68
|
+
::ActiveRecord::Associations::AssociationCollection.send(:include, Pagination)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'folio'
|
2
|
+
require 'folio/ordinal/page'
|
3
|
+
require 'will_paginate/collection'
|
4
|
+
|
5
|
+
# overrides WillPaginate::Collection.create to return an ordinal folio page
|
6
|
+
# instead of a WillPaginate::Collection; the rest of WillPaginate::Collection
|
7
|
+
# is unused when in folio-land.
|
8
|
+
module WillPaginate
|
9
|
+
class Collection
|
10
|
+
def self.create(current_page, per_page=nil, total_entries=nil)
|
11
|
+
page = ::Folio::Ordinal::Page.create
|
12
|
+
page.current_page = current_page
|
13
|
+
page.per_page = per_page
|
14
|
+
page.total_entries = total_entries
|
15
|
+
yield page if block_given?
|
16
|
+
page
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'folio'
|
2
|
+
require 'folio/will_paginate/view_helpers/link_renderer'
|
3
|
+
require 'will_paginate/view_helpers'
|
4
|
+
|
5
|
+
module Folio
|
6
|
+
module WillPaginate
|
7
|
+
module ViewHelpers
|
8
|
+
# just copied from ::WillPaginate::ViewHelpers except line 20 (changed from
|
9
|
+
# "unless value > 1" to "if value == 1" to be friendly to unknown
|
10
|
+
# total_pages)
|
11
|
+
def will_paginate_with_folio(collection = nil, options = {})
|
12
|
+
options, collection = collection, nil if collection.is_a? Hash
|
13
|
+
unless collection or !controller
|
14
|
+
collection_name = "@#{controller.controller_name}"
|
15
|
+
collection = instance_variable_get(collection_name)
|
16
|
+
raise ArgumentError, "The #{collection_name} variable appears to be empty. Did you " +
|
17
|
+
"forget to pass the collection object for will_paginate?" unless collection
|
18
|
+
end
|
19
|
+
# early exit if there is nothing to render
|
20
|
+
return nil if ::WillPaginate::ViewHelpers.total_pages_for_collection(collection) == 1
|
21
|
+
|
22
|
+
options = options.symbolize_keys.reverse_merge ::WillPaginate::ViewHelpers.pagination_options
|
23
|
+
if options[:prev_label]
|
24
|
+
WillPaginate::Deprecation::warn(":prev_label view parameter is now :previous_label; the old name has been deprecated", caller)
|
25
|
+
options[:previous_label] = options.delete(:prev_label)
|
26
|
+
end
|
27
|
+
|
28
|
+
# get the renderer instance
|
29
|
+
renderer = case options[:renderer]
|
30
|
+
when String
|
31
|
+
options[:renderer].to_s.constantize.new
|
32
|
+
when Class
|
33
|
+
options[:renderer].new
|
34
|
+
else
|
35
|
+
options[:renderer]
|
36
|
+
end
|
37
|
+
# render HTML for pagination
|
38
|
+
renderer.prepare collection, options, self
|
39
|
+
renderer.to_html
|
40
|
+
end
|
41
|
+
|
42
|
+
def page_entries_info_with_folio(collection, options = {})
|
43
|
+
# skip outputting anything unless the collection has ordinal pages (to
|
44
|
+
# be able to get an offset) *and* a known total count.
|
45
|
+
return unless collection.total_entries && collection.ordinal_pages
|
46
|
+
page_entries_info_without_folio(collection, options)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.included(klass)
|
50
|
+
[:will_paginate, :page_entries_info].each do |method|
|
51
|
+
klass.send(:alias_method, :"#{method}_without_folio", method)
|
52
|
+
klass.send(:alias_method, method, :"#{method}_with_folio")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
::WillPaginate::ViewHelpers.send :include, self
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|