kaminari-jets-core 0.2.0

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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.md +31 -0
  5. data/app/views/kaminari/_first_page.html.erb +11 -0
  6. data/app/views/kaminari/_first_page.html.haml +9 -0
  7. data/app/views/kaminari/_first_page.html.slim +10 -0
  8. data/app/views/kaminari/_gap.html.erb +8 -0
  9. data/app/views/kaminari/_gap.html.haml +8 -0
  10. data/app/views/kaminari/_gap.html.slim +9 -0
  11. data/app/views/kaminari/_last_page.html.erb +11 -0
  12. data/app/views/kaminari/_last_page.html.haml +9 -0
  13. data/app/views/kaminari/_last_page.html.slim +10 -0
  14. data/app/views/kaminari/_next_page.html.erb +11 -0
  15. data/app/views/kaminari/_next_page.html.haml +9 -0
  16. data/app/views/kaminari/_next_page.html.slim +10 -0
  17. data/app/views/kaminari/_page.html.erb +12 -0
  18. data/app/views/kaminari/_page.html.haml +10 -0
  19. data/app/views/kaminari/_page.html.slim +11 -0
  20. data/app/views/kaminari/_paginator.html.erb +25 -0
  21. data/app/views/kaminari/_paginator.html.haml +18 -0
  22. data/app/views/kaminari/_paginator.html.slim +19 -0
  23. data/app/views/kaminari/_prev_page.html.erb +11 -0
  24. data/app/views/kaminari/_prev_page.html.haml +9 -0
  25. data/app/views/kaminari/_prev_page.html.slim +10 -0
  26. data/config/locales/kaminari.yml +23 -0
  27. data/kaminari-core.gemspec +26 -0
  28. data/lib/generators/kaminari/config_generator.rb +19 -0
  29. data/lib/generators/kaminari/templates/kaminari_config.rb +14 -0
  30. data/lib/generators/kaminari/views_generator.rb +137 -0
  31. data/lib/kaminari/config.rb +40 -0
  32. data/lib/kaminari/core/version.rb +8 -0
  33. data/lib/kaminari/core.rb +29 -0
  34. data/lib/kaminari/engine.rb +6 -0
  35. data/lib/kaminari/exceptions.rb +5 -0
  36. data/lib/kaminari/helpers/helper_methods.rb +247 -0
  37. data/lib/kaminari/helpers/paginator.rb +191 -0
  38. data/lib/kaminari/helpers/tags.rb +164 -0
  39. data/lib/kaminari/jets/engine.rb +6 -0
  40. data/lib/kaminari/jets/turbine.rb +9 -0
  41. data/lib/kaminari/models/array_extension.rb +73 -0
  42. data/lib/kaminari/models/configuration_methods.rb +60 -0
  43. data/lib/kaminari/models/page_scope_methods.rb +91 -0
  44. data/lib/kaminari/railtie.rb +9 -0
  45. metadata +115 -0
@@ -0,0 +1,247 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kaminari
4
+ module Helpers
5
+
6
+ # The Kaminari::Helpers::UrlHelper module provides useful methods for
7
+ # generating a path or url to a particular page. A class must implement the
8
+ # following methods:
9
+ #
10
+ # * <tt>url_for</tt>: A method that generates an actual path
11
+ # * <tt>params</tt>: A method that returns query string parameters
12
+ # * <tt>request</tt>: A method that returns a Rack::Request object
13
+ #
14
+ # A normal Rails controller implements all the methods, which make it
15
+ # trivial to use this module:
16
+ #
17
+ # ==== Examples
18
+ #
19
+ # class UsersController < ApplicationController
20
+ # include Kaminari::Helpers::UrlHelper
21
+ #
22
+ # def index
23
+ # @users = User.page(1)
24
+ #
25
+ # path_to_next_page(@items)
26
+ # # => /items?page=2
27
+ # end
28
+ # end
29
+ #
30
+ module UrlHelper
31
+
32
+ # A helper that calculates the url to the next page.
33
+ #
34
+ # ==== Examples
35
+ # Basic usage:
36
+ #
37
+ # <%= next_page_url @items %>
38
+ # #-> http://www.example.org/items?page=2
39
+ #
40
+ # It will return `nil` if there is no next page.
41
+ def next_page_url(scope, options = {})
42
+ "#{request.base_url}#{next_page_path(scope, options)}" if scope.next_page
43
+ end
44
+ alias url_to_next_page next_page_url
45
+
46
+ def path_to_next_url(scope, options = {})
47
+ ActiveSupport::Deprecation.warn 'path_to_next_url is deprecated. Use next_page_url or url_to_next_page instead.'
48
+ next_page_url(scope, options)
49
+ end
50
+
51
+ # A helper that calculates the url to the previous page.
52
+ #
53
+ # ==== Examples
54
+ # Basic usage:
55
+ #
56
+ # <%= prev_page_url @items %>
57
+ # #-> http://www.example.org/items
58
+ #
59
+ # It will return `nil` if there is no previous page.
60
+ def prev_page_url(scope, options = {})
61
+ "#{request.base_url}#{prev_page_path(scope, options)}" if scope.prev_page
62
+ end
63
+ alias previous_page_url prev_page_url
64
+ alias url_to_prev_page prev_page_url
65
+ alias url_to_previous_page prev_page_url
66
+
67
+ # A helper that calculates the path to the next page.
68
+ #
69
+ # ==== Examples
70
+ # Basic usage:
71
+ #
72
+ # <%= path_to_next_page @items %>
73
+ # #-> /items?page=2
74
+ #
75
+ # It will return `nil` if there is no next page.
76
+ def next_page_path(scope, options = {})
77
+ Kaminari::Helpers::NextPage.new(self, **options.reverse_merge(current_page: scope.current_page)).url if scope.next_page
78
+ end
79
+ alias path_to_next_page next_page_path
80
+
81
+ # A helper that calculates the path to the previous page.
82
+ #
83
+ # ==== Examples
84
+ # Basic usage:
85
+ #
86
+ # <%= path_to_prev_page @items %>
87
+ # #-> /items
88
+ #
89
+ # It will return `nil` if there is no previous page.
90
+ def prev_page_path(scope, options = {})
91
+ Kaminari::Helpers::PrevPage.new(self, **options.reverse_merge(current_page: scope.current_page)).url if scope.prev_page
92
+ end
93
+ alias previous_page_path prev_page_path
94
+ alias path_to_previous_page prev_page_path
95
+ alias path_to_prev_page prev_page_path
96
+ end
97
+
98
+ module HelperMethods
99
+ include UrlHelper
100
+
101
+ # A helper that renders the pagination links.
102
+ #
103
+ # <%= paginate @articles %>
104
+ #
105
+ # ==== Options
106
+ # * <tt>:window</tt> - The "inner window" size (4 by default).
107
+ # * <tt>:outer_window</tt> - The "outer window" size (0 by default).
108
+ # * <tt>:left</tt> - The "left outer window" size (0 by default).
109
+ # * <tt>:right</tt> - The "right outer window" size (0 by default).
110
+ # * <tt>:params</tt> - url_for parameters for the links (:controller, :action, etc.)
111
+ # * <tt>:param_name</tt> - parameter name for page number in the links (:page by default)
112
+ # * <tt>:remote</tt> - Ajax? (false by default)
113
+ # * <tt>:paginator_class</tt> - Specify a custom Paginator (Kaminari::Helpers::Paginator by default)
114
+ # * <tt>:template</tt> - Specify a custom template renderer for rendering the Paginator (receiver by default)
115
+ # * <tt>:ANY_OTHER_VALUES</tt> - Any other hash key & values would be directly passed into each tag as :locals value.
116
+ def paginate(scope, paginator_class: Kaminari::Helpers::Paginator, template: nil, **options)
117
+ options[:total_pages] ||= scope.total_pages
118
+ options.reverse_merge! current_page: scope.current_page, per_page: scope.limit_value, remote: false
119
+
120
+ paginator = paginator_class.new (template || self), **options
121
+ paginator.to_s
122
+ end
123
+
124
+ # A simple "Twitter like" pagination link that creates a link to the previous page.
125
+ #
126
+ # ==== Examples
127
+ # Basic usage:
128
+ #
129
+ # <%= link_to_previous_page @items, 'Previous Page' %>
130
+ #
131
+ # Ajax:
132
+ #
133
+ # <%= link_to_previous_page @items, 'Previous Page', remote: true %>
134
+ #
135
+ # By default, it renders nothing if there are no more results on the previous page.
136
+ # You can customize this output by passing a block.
137
+ #
138
+ # <%= link_to_previous_page @users, 'Previous Page' do %>
139
+ # <span>At the Beginning</span>
140
+ # <% end %>
141
+ def link_to_previous_page(scope, name, **options)
142
+ prev_page = path_to_prev_page(scope, options)
143
+
144
+ options.except! :params, :param_name
145
+ options[:rel] ||= 'prev'
146
+
147
+ if prev_page
148
+ link_to name, prev_page, options
149
+ elsif block_given?
150
+ yield
151
+ end
152
+ end
153
+ alias link_to_prev_page link_to_previous_page
154
+
155
+ # A simple "Twitter like" pagination link that creates a link to the next page.
156
+ #
157
+ # ==== Examples
158
+ # Basic usage:
159
+ #
160
+ # <%= link_to_next_page @items, 'Next Page' %>
161
+ #
162
+ # Ajax:
163
+ #
164
+ # <%= link_to_next_page @items, 'Next Page', remote: true %>
165
+ #
166
+ # By default, it renders nothing if there are no more results on the next page.
167
+ # You can customize this output by passing a block.
168
+ #
169
+ # <%= link_to_next_page @users, 'Next Page' do %>
170
+ # <span>No More Pages</span>
171
+ # <% end %>
172
+ def link_to_next_page(scope, name, **options)
173
+ next_page = path_to_next_page(scope, options)
174
+
175
+ options.except! :params, :param_name
176
+ options[:rel] ||= 'next'
177
+
178
+ if next_page
179
+ link_to name, next_page, options
180
+ elsif block_given?
181
+ yield
182
+ end
183
+ end
184
+
185
+ # Renders a helpful message with numbers of displayed vs. total entries.
186
+ # Ported from mislav/will_paginate
187
+ #
188
+ # ==== Examples
189
+ # Basic usage:
190
+ #
191
+ # <%= page_entries_info @posts %>
192
+ # #-> Displaying posts 6 - 10 of 26 in total
193
+ #
194
+ # By default, the message will use the humanized class name of objects
195
+ # in collection: for instance, "project types" for ProjectType models.
196
+ # The namespace will be cutted out and only the last name will be used.
197
+ # Override this with the <tt>:entry_name</tt> parameter:
198
+ #
199
+ # <%= page_entries_info @posts, entry_name: 'item' %>
200
+ # #-> Displaying items 6 - 10 of 26 in total
201
+ def page_entries_info(collection, entry_name: nil)
202
+ entry_name = if entry_name
203
+ entry_name.pluralize(collection.size, I18n.locale)
204
+ else
205
+ collection.entry_name(count: collection.size).downcase
206
+ end
207
+
208
+ if collection.total_pages < 2
209
+ t('helpers.page_entries_info.one_page.display_entries', entry_name: entry_name, count: collection.total_count)
210
+ else
211
+ from = collection.offset_value + 1
212
+ to = collection.offset_value + (collection.respond_to?(:records) ? collection.records : collection.to_a).size
213
+
214
+ t('helpers.page_entries_info.more_pages.display_entries', entry_name: entry_name, first: from, last: to, total: collection.total_count)
215
+ end.html_safe
216
+ end
217
+
218
+ # Renders rel="next" and rel="prev" links to be used in the head.
219
+ #
220
+ # ==== Examples
221
+ # Basic usage:
222
+ #
223
+ # In head:
224
+ # <head>
225
+ # <title>My Website</title>
226
+ # <%= yield :head %>
227
+ # </head>
228
+ #
229
+ # Somewhere in body:
230
+ # <% content_for :head do %>
231
+ # <%= rel_next_prev_link_tags @items %>
232
+ # <% end %>
233
+ #
234
+ # #-> <link rel="next" href="/items/page/3"><link rel="prev" href="/items/page/1">
235
+ #
236
+ def rel_next_prev_link_tags(scope, options = {})
237
+ next_page = path_to_next_page(scope, options)
238
+ prev_page = path_to_prev_page(scope, options)
239
+
240
+ output = String.new
241
+ output << %Q|<link rel="next" href="#{next_page}">| if next_page
242
+ output << %Q|<link rel="prev" href="#{prev_page}">| if prev_page
243
+ output.html_safe
244
+ end
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/inflector'
4
+ require 'kaminari/helpers/tags'
5
+
6
+ module Kaminari
7
+ module Helpers
8
+ # The main container tag
9
+ class Paginator < Tag
10
+ def initialize(template, window: nil, outer_window: Kaminari.config.outer_window, left: Kaminari.config.left, right: Kaminari.config.right, inner_window: Kaminari.config.window, **options) #:nodoc:
11
+ @window_options = {window: window || inner_window, left: left.zero? ? outer_window : left, right: right.zero? ? outer_window : right}
12
+
13
+ @template, @options, @theme, @views_prefix, @last = template, options, options[:theme], options[:views_prefix], nil
14
+ @window_options.merge! @options
15
+ @window_options[:current_page] = @options[:current_page] = PageProxy.new(@window_options, @options[:current_page], nil)
16
+
17
+ #XXX Using parent template's buffer class for rendering each partial here. This might cause problems if the handler mismatches
18
+ @output_buffer = if defined?(::ActionView::OutputBuffer)
19
+ ::ActionView::OutputBuffer.new
20
+ elsif template.instance_variable_get(:@output_buffer)
21
+ template.instance_variable_get(:@output_buffer).class.new
22
+ else
23
+ ActiveSupport::SafeBuffer.new
24
+ end
25
+ end
26
+
27
+ # render given block as a view template
28
+ def render(&block)
29
+ instance_eval(&block) if @options[:total_pages] > 1
30
+
31
+ # This allows for showing fall-back HTML when there's only one page:
32
+ #
33
+ # <%= paginate(@search_results) || "Showing all search results" %>
34
+ @output_buffer.presence
35
+ end
36
+
37
+ # enumerate each page providing PageProxy object as the block parameter
38
+ # Because of performance reason, this doesn't actually enumerate all pages but pages that are seemingly relevant to the paginator.
39
+ # "Relevant" pages are:
40
+ # * pages inside the left outer window plus one for showing the gap tag
41
+ # * pages inside the inner window plus one on the left plus one on the right for showing the gap tags
42
+ # * pages inside the right outer window plus one for showing the gap tag
43
+ def each_relevant_page
44
+ return to_enum(:each_relevant_page) unless block_given?
45
+
46
+ relevant_pages(@window_options).each do |page|
47
+ yield PageProxy.new(@window_options, page, @last)
48
+ end
49
+ end
50
+ alias each_page each_relevant_page
51
+
52
+ def relevant_pages(options)
53
+ left_window_plus_one = [*1..options[:left] + 1]
54
+ right_window_plus_one = [*options[:total_pages] - options[:right]..options[:total_pages]]
55
+ inside_window_plus_each_sides = [*options[:current_page] - options[:window] - 1..options[:current_page] + options[:window] + 1]
56
+
57
+ (left_window_plus_one | inside_window_plus_each_sides | right_window_plus_one).sort.reject {|x| (x < 1) || (x > options[:total_pages])}
58
+ end
59
+ private :relevant_pages
60
+
61
+ def page_tag(page)
62
+ @last = Page.new @template, **@options.merge(page: page)
63
+ end
64
+
65
+ %w[first_page prev_page next_page last_page gap].each do |tag|
66
+ eval <<-DEF, nil, __FILE__, __LINE__ + 1
67
+ def #{tag}_tag
68
+ @last = #{tag.classify}.new @template, **@options
69
+ end
70
+ DEF
71
+ end
72
+
73
+ def to_s #:nodoc:
74
+ Thread.current[:kaminari_rendering] = true
75
+ super @window_options.merge paginator: self
76
+ ensure
77
+ Thread.current[:kaminari_rendering] = false
78
+ end
79
+
80
+ # delegates view helper methods to @template
81
+ def method_missing(name, *args, &block)
82
+ @template.respond_to?(name) ? @template.send(name, *args, &block) : super
83
+ end
84
+ private :method_missing
85
+
86
+ # Wraps a "page number" and provides some utility methods
87
+ class PageProxy
88
+ include Comparable
89
+
90
+ def initialize(options, page, last) #:nodoc:
91
+ @options, @page, @last = options, page, last
92
+ end
93
+
94
+ # the page number
95
+ def number
96
+ @page
97
+ end
98
+
99
+ # current page or not
100
+ def current?
101
+ @page == @options[:current_page]
102
+ end
103
+
104
+ # the first page or not
105
+ def first?
106
+ @page == 1
107
+ end
108
+
109
+ # the last page or not
110
+ def last?
111
+ @page == @options[:total_pages]
112
+ end
113
+
114
+ # the previous page or not
115
+ def prev?
116
+ @page == @options[:current_page] - 1
117
+ end
118
+
119
+ # the next page or not
120
+ def next?
121
+ @page == @options[:current_page] + 1
122
+ end
123
+
124
+ # relationship with the current page
125
+ def rel
126
+ if next?
127
+ 'next'
128
+ elsif prev?
129
+ 'prev'
130
+ end
131
+ end
132
+
133
+ # within the left outer window or not
134
+ def left_outer?
135
+ @page <= @options[:left]
136
+ end
137
+
138
+ # within the right outer window or not
139
+ def right_outer?
140
+ @options[:total_pages] - @page < @options[:right]
141
+ end
142
+
143
+ # inside the inner window or not
144
+ def inside_window?
145
+ (@options[:current_page] - @page).abs <= @options[:window]
146
+ end
147
+
148
+ # Current page is an isolated gap or not
149
+ def single_gap?
150
+ ((@page == @options[:current_page] - @options[:window] - 1) && (@page == @options[:left] + 1)) ||
151
+ ((@page == @options[:current_page] + @options[:window] + 1) && (@page == @options[:total_pages] - @options[:right]))
152
+ end
153
+
154
+ # The page number exceeds the range of pages or not
155
+ def out_of_range?
156
+ @page > @options[:total_pages]
157
+ end
158
+
159
+ # The last rendered tag was "truncated" or not
160
+ def was_truncated?
161
+ @last.is_a? Gap
162
+ end
163
+
164
+ #Should we display the link tag?
165
+ def display_tag?
166
+ left_outer? || right_outer? || inside_window? || single_gap?
167
+ end
168
+
169
+ def to_i #:nodoc:
170
+ number
171
+ end
172
+
173
+ def to_s #:nodoc:
174
+ number.to_s
175
+ end
176
+
177
+ def +(other) #:nodoc:
178
+ to_i + other.to_i
179
+ end
180
+
181
+ def -(other) #:nodoc:
182
+ to_i - other.to_i
183
+ end
184
+
185
+ def <=>(other) #:nodoc:
186
+ to_i <=> other.to_i
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kaminari
4
+ module Helpers
5
+ PARAM_KEY_EXCEPT_LIST = [:authenticity_token, :commit, :utf8, :_method, :script_name, :original_script_name].freeze
6
+
7
+ # A tag stands for an HTML tag inside the paginator.
8
+ # Basically, a tag has its own partial template file, so every tag can be
9
+ # rendered into String using its partial template.
10
+ #
11
+ # The template file should be placed in your app/views/kaminari/ directory
12
+ # with underscored class name (besides the "Tag" class. Tag is an abstract
13
+ # class, so _tag partial is not needed).
14
+ # e.g.) PrevLink -> app/views/kaminari/_prev_link.html.erb
15
+ #
16
+ # When no matching templates were found in your app, the engine's pre
17
+ # installed template will be used.
18
+ # e.g.) Paginator -> $GEM_HOME/kaminari-x.x.x/app/views/kaminari/_paginator.html.erb
19
+ class Tag
20
+ def initialize(template, params: {}, param_name: nil, theme: nil, views_prefix: nil, **options) #:nodoc:
21
+ @template, @theme, @views_prefix, @options = template, theme, views_prefix, options
22
+ @param_name = param_name || Kaminari.config.param_name
23
+ @params = template.params
24
+ # @params in Rails 5 no longer inherits from Hash
25
+ @params = @params.to_unsafe_h if @params.respond_to?(:to_unsafe_h)
26
+ @params = @params.with_indifferent_access
27
+ @params.except!(*PARAM_KEY_EXCEPT_LIST)
28
+ @params.merge! params
29
+ end
30
+
31
+ def to_s(locals = {}) #:nodoc:
32
+ formats = (@template.respond_to?(:formats) ? @template.formats : Array(@template.params[:format])) + [:html]
33
+ @template.render partial: partial_path, locals: @options.merge(locals), formats: formats
34
+ end
35
+
36
+ def page_url_for(page)
37
+ params = params_for(page)
38
+ params[:only_path] = true
39
+ @template.url_for params
40
+ end
41
+
42
+ private
43
+
44
+ def params_for(page)
45
+ page_params = Rack::Utils.parse_nested_query("#{@param_name}=#{page}")
46
+ page_params = @params.deep_merge(page_params)
47
+
48
+ if !Kaminari.config.params_on_first_page && (page <= 1)
49
+ # This converts a hash:
50
+ # from: {other: "params", page: 1}
51
+ # to: {other: "params", page: nil}
52
+ # (when @param_name == "page")
53
+ #
54
+ # from: {other: "params", user: {name: "yuki", page: 1}}
55
+ # to: {other: "params", user: {name: "yuki", page: nil}}
56
+ # (when @param_name == "user[page]")
57
+ @param_name.to_s.scan(/[\w\.]+/)[0..-2].inject(page_params){|h, k| h[k] }[$&] = nil
58
+ end
59
+
60
+ page_params
61
+ end
62
+
63
+ def partial_path
64
+ [
65
+ @views_prefix,
66
+ "kaminari",
67
+ @theme,
68
+ self.class.name.demodulize.underscore
69
+ ].compact.join("/").gsub('//', '/')
70
+ end
71
+ end
72
+
73
+ # Tag that contains a link
74
+ module Link
75
+ # target page number
76
+ def page
77
+ raise 'Override page with the actual page value to be a Page.'
78
+ end
79
+ # the link's href
80
+ def url
81
+ page_url_for page
82
+ end
83
+ def to_s(locals = {}) #:nodoc:
84
+ locals[:url] = url
85
+ super locals
86
+ end
87
+ end
88
+
89
+ # A page
90
+ class Page < Tag
91
+ include Link
92
+ # target page number
93
+ def page
94
+ @options[:page]
95
+ end
96
+ def to_s(locals = {}) #:nodoc:
97
+ locals[:page] = page
98
+ super locals
99
+ end
100
+ end
101
+
102
+ # Link with page number that appears at the leftmost
103
+ class FirstPage < Tag
104
+ include Link
105
+ def page #:nodoc:
106
+ 1
107
+ end
108
+ end
109
+
110
+ # Link with page number that appears at the rightmost
111
+ class LastPage < Tag
112
+ include Link
113
+ def page #:nodoc:
114
+ @options[:total_pages]
115
+ end
116
+ end
117
+
118
+ # The "previous" page of the current page
119
+ class PrevPage < Tag
120
+ include Link
121
+
122
+ # TODO: Remove this initializer before 1.3.0.
123
+ def initialize(template, params: {}, param_name: nil, theme: nil, views_prefix: nil, **options) #:nodoc:
124
+ # params in Rails 5 may not be a Hash either,
125
+ # so it must be converted to a Hash to be merged into @params
126
+ if params && params.respond_to?(:to_unsafe_h)
127
+ ActiveSupport::Deprecation.warn 'Explicitly passing params to helpers could be omitted.'
128
+ params = params.to_unsafe_h
129
+ end
130
+
131
+ super(template, params: params, param_name: param_name, theme: theme, views_prefix: views_prefix, **options)
132
+ end
133
+
134
+ def page #:nodoc:
135
+ @options[:current_page] - 1
136
+ end
137
+ end
138
+
139
+ # The "next" page of the current page
140
+ class NextPage < Tag
141
+ include Link
142
+
143
+ # TODO: Remove this initializer before 1.3.0.
144
+ def initialize(template, params: {}, param_name: nil, theme: nil, views_prefix: nil, **options) #:nodoc:
145
+ # params in Rails 5 may not be a Hash either,
146
+ # so it must be converted to a Hash to be merged into @params
147
+ if params && params.respond_to?(:to_unsafe_h)
148
+ ActiveSupport::Deprecation.warn 'Explicitly passing params to helpers could be omitted.'
149
+ params = params.to_unsafe_h
150
+ end
151
+
152
+ super(template, params: params, param_name: param_name, theme: theme, views_prefix: views_prefix, **options)
153
+ end
154
+
155
+ def page #:nodoc:
156
+ @options[:current_page] + 1
157
+ end
158
+ end
159
+
160
+ # Non-link tag that stands for skipped pages...
161
+ class Gap < Tag
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kaminari #:nodoc:
4
+ class Engine < ::Jets::Engine #:nodoc:
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kaminari
4
+ class Turbine < ::Jets::Turbine #:nodoc:
5
+ # Doesn't actually do anything. Just keeping this hook point, mainly for compatibility
6
+ initializer 'kaminari' do
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/module'
4
+ module Kaminari
5
+ # Kind of Array that can paginate
6
+ class PaginatableArray < Array
7
+ include Kaminari::ConfigurationMethods::ClassMethods
8
+
9
+ ENTRY = 'entry'.freeze
10
+
11
+ attr_internal_accessor :limit_value, :offset_value
12
+
13
+ # ==== Options
14
+ # * <tt>:limit</tt> - limit
15
+ # * <tt>:offset</tt> - offset
16
+ # * <tt>:total_count</tt> - total_count
17
+ # * <tt>:padding</tt> - padding
18
+ def initialize(original_array = [], limit: nil, offset: nil, total_count: nil, padding: nil)
19
+ @_original_array, @_limit_value, @_offset_value, @_total_count, @_padding = original_array, (limit || default_per_page).to_i, offset.to_i, total_count, padding.to_i
20
+
21
+ if limit && offset
22
+ extend Kaminari::PageScopeMethods
23
+ end
24
+
25
+ if @_total_count && (@_total_count <= original_array.count)
26
+ original_array = original_array.first(@_total_count)[@_offset_value, @_limit_value]
27
+ end
28
+
29
+ unless @_total_count
30
+ original_array = original_array[@_offset_value, @_limit_value]
31
+ end
32
+
33
+ super(original_array || [])
34
+ end
35
+
36
+ # Used for page_entry_info
37
+ def entry_name(options = {})
38
+ I18n.t('helpers.page_entries_info.entry', **options.reverse_merge(default: ENTRY.pluralize(options[:count])))
39
+ end
40
+
41
+ # items at the specified "page"
42
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
43
+ def #{Kaminari.config.page_method_name}(num = 1)
44
+ offset(limit_value * ((num = num.to_i - 1) < 0 ? 0 : num))
45
+ end
46
+ RUBY
47
+
48
+ # returns another chunk of the original array
49
+ def limit(num)
50
+ self.class.new @_original_array, limit: num, offset: @_offset_value, total_count: @_total_count, padding: @_padding
51
+ end
52
+
53
+ # total item numbers of the original array
54
+ def total_count
55
+ @_total_count || @_original_array.length
56
+ end
57
+
58
+ # returns another chunk of the original array
59
+ def offset(num)
60
+ self.class.new @_original_array, limit: @_limit_value, offset: num, total_count: @_total_count, padding: @_padding
61
+ end
62
+ end
63
+
64
+ # Wrap an Array object to make it paginatable
65
+ # ==== Options
66
+ # * <tt>:limit</tt> - limit
67
+ # * <tt>:offset</tt> - offset
68
+ # * <tt>:total_count</tt> - total_count
69
+ # * <tt>:padding</tt> - padding
70
+ def self.paginate_array(array, limit: nil, offset: nil, total_count: nil, padding: nil)
71
+ PaginatableArray.new array, limit: limit, offset: offset, total_count: total_count, padding: padding
72
+ end
73
+ end