folio-pagination-legacy 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|