mirror of
https://github.com/kaminari/kaminari.git
synced 2022-11-09 13:44:37 -05:00
WIP
This commit is contained in:
parent
b8b6b98c3a
commit
fece8b9f72
6 changed files with 64 additions and 211 deletions
|
@ -3,6 +3,7 @@ source 'https://rubygems.org'
|
||||||
gem 'railties', '~> 5.1.0'
|
gem 'railties', '~> 5.1.0'
|
||||||
gem 'activerecord', '~> 5.1.0', require: 'active_record'
|
gem 'activerecord', '~> 5.1.0', require: 'active_record'
|
||||||
gem 'actionview', '~> 5.1.0', require: 'action_view'
|
gem 'actionview', '~> 5.1.0', require: 'action_view'
|
||||||
|
gem 'byebug'
|
||||||
|
|
||||||
platforms :ruby do
|
platforms :ruby do
|
||||||
gem 'sqlite3', require: false
|
gem 'sqlite3', require: false
|
||||||
|
|
|
@ -6,20 +6,8 @@
|
||||||
remote: data-remote
|
remote: data-remote
|
||||||
paginator: the paginator that renders the pagination tags inside
|
paginator: the paginator that renders the pagination tags inside
|
||||||
-%>
|
-%>
|
||||||
<%= paginator.render do -%>
|
<nav class="pagination" role="navigation" aria-label="pager">
|
||||||
<nav class="pagination" role="navigation" aria-label="pager">
|
<% paginator.each_page do |page_tag| %>
|
||||||
<%= first_page_tag unless current_page.first? %>
|
<%= render page_tag, url: paginator.page_url_for(page_tag), remote: false, current_page: page_tag.current_page %>
|
||||||
<%= prev_page_tag unless current_page.first? %>
|
|
||||||
<% each_page do |page| -%>
|
|
||||||
<% if page.display_tag? -%>
|
|
||||||
<%= page_tag page %>
|
|
||||||
<% elsif !page.was_truncated? -%>
|
|
||||||
<%= gap_tag %>
|
|
||||||
<% end -%>
|
|
||||||
<% end -%>
|
|
||||||
<% unless current_page.out_of_range? %>
|
|
||||||
<%= next_page_tag unless current_page.last? %>
|
|
||||||
<%= last_page_tag unless current_page.last? %>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
</nav>
|
</nav>
|
||||||
<% end -%>
|
|
||||||
|
|
|
@ -22,8 +22,7 @@ module Kaminari
|
||||||
options[:total_pages] ||= scope.total_pages
|
options[:total_pages] ||= scope.total_pages
|
||||||
options.reverse_merge! current_page: scope.current_page, per_page: scope.limit_value, remote: false
|
options.reverse_merge! current_page: scope.current_page, per_page: scope.limit_value, remote: false
|
||||||
|
|
||||||
paginator = paginator_class.new (template || self), options
|
render paginator_class.new(router: Kaminari::Helpers::Tag.new((template || self), options), **options)
|
||||||
paginator.to_s
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# A simple "Twitter like" pagination link that creates a link to the previous page.
|
# A simple "Twitter like" pagination link that creates a link to the previous page.
|
||||||
|
|
|
@ -5,32 +5,21 @@ require 'kaminari/helpers/tags'
|
||||||
module Kaminari
|
module Kaminari
|
||||||
module Helpers
|
module Helpers
|
||||||
# The main container tag
|
# The main container tag
|
||||||
class Paginator < Tag
|
class Paginator
|
||||||
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:
|
def initialize(router: , window: nil, outer_window: Kaminari.config.outer_window, left: Kaminari.config.left, right: Kaminari.config.right, inner_window: Kaminari.config.window, **options) #:nodoc:
|
||||||
@window_options = {window: window || inner_window, left: left.zero? ? outer_window : left, right: right.zero? ? outer_window : right}
|
@window_options = {window: window || inner_window, left: left.zero? ? outer_window : left, right: right.zero? ? outer_window : right}
|
||||||
|
|
||||||
@template, @options, @theme, @views_prefix, @last = template, options, options[:theme], options[:views_prefix], nil
|
@router, @options, @theme, @views_prefix, @last = router, options, options[:theme], options[:views_prefix], nil
|
||||||
@window_options.merge! @options
|
@window_options.merge! @options
|
||||||
@window_options[:current_page] = @options[:current_page] = PageProxy.new(@window_options, @options[:current_page], nil)
|
@window_options[:current_page] = @options[:current_page]
|
||||||
|
|
||||||
#XXX Using parent template's buffer class for rendering each partial here. This might cause problems if the handler mismatches
|
|
||||||
@output_buffer = if defined?(::ActionView::OutputBuffer)
|
|
||||||
::ActionView::OutputBuffer.new
|
|
||||||
elsif template.instance_variable_get(:@output_buffer)
|
|
||||||
template.instance_variable_get(:@output_buffer).class.new
|
|
||||||
else
|
|
||||||
ActiveSupport::SafeBuffer.new
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# render given block as a view template
|
def page_url_for(page_tag)
|
||||||
def render(&block)
|
@router.page_url_for(page_tag.page)
|
||||||
instance_eval(&block) if @options[:total_pages] > 1
|
end
|
||||||
|
|
||||||
# This allows for showing fall-back HTML when there's only one page:
|
def to_partial_path
|
||||||
#
|
[ @views_prefix, "kaminari", @theme, self.class.name.demodulize.underscore ].compact.join("/")
|
||||||
# <%= paginate(@search_results) || "Showing all search results" %>
|
|
||||||
@output_buffer.presence
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# enumerate each page providing PageProxy object as the block parameter
|
# enumerate each page providing PageProxy object as the block parameter
|
||||||
|
@ -42,147 +31,72 @@ module Kaminari
|
||||||
def each_relevant_page
|
def each_relevant_page
|
||||||
return to_enum(:each_relevant_page) unless block_given?
|
return to_enum(:each_relevant_page) unless block_given?
|
||||||
|
|
||||||
relevant_pages(@window_options).each do |page|
|
current_page, total_pages = @options[:current_page], @options[:total_pages]
|
||||||
yield PageProxy.new(@window_options, page, @last)
|
|
||||||
end
|
[
|
||||||
|
FirstPage.new(page: 1, current: current_page, theme: @theme, views_prefix: @views_prefix),
|
||||||
|
PrevPage.new(page: current_page - 1, current: current_page, theme: @theme, views_prefix: @views_prefix),
|
||||||
|
relevant_pages.map { |page| Page.new(page: page, current: current_page, theme: @theme, views_prefix: @views_prefix) },
|
||||||
|
NextPage.new(page: current_page + 1, current: current_page, theme: @theme, views_prefix: @views_prefix),
|
||||||
|
LastPage.new(page: total_pages, current: current_page, theme: @theme, views_prefix: @views_prefix),
|
||||||
|
].flatten.each {|page| yield page }
|
||||||
end
|
end
|
||||||
alias each_page each_relevant_page
|
alias each_page each_relevant_page
|
||||||
|
|
||||||
def relevant_pages(options)
|
def relevant_pages(options = @window_options)
|
||||||
left_window_plus_one = [*1..options[:left] + 1]
|
left_window_plus_one = [*1..options[:left] + 1]
|
||||||
right_window_plus_one = [*options[:total_pages] - options[:right]..options[:total_pages]]
|
right_window_plus_one = [*options[:total_pages] - options[:right]..options[:total_pages]]
|
||||||
inside_window_plus_each_sides = [*options[:current_page] - options[:window] - 1..options[:current_page] + options[:window] + 1]
|
inside_window_plus_each_sides = [*options[:current_page] - options[:window] - 1..options[:current_page] + options[:window] + 1]
|
||||||
|
|
||||||
(left_window_plus_one | inside_window_plus_each_sides | right_window_plus_one).sort.reject {|x| (x < 1) || (x > options[:total_pages])}
|
(left_window_plus_one | inside_window_plus_each_sides | right_window_plus_one).sort.reject {|x| (x < 1) || (x > options[:total_pages])}
|
||||||
end
|
end
|
||||||
private :relevant_pages
|
|
||||||
|
|
||||||
def page_tag(page)
|
class Page
|
||||||
@last = Page.new @template, @options.merge(page: page)
|
attr_reader :page, :current, :rel
|
||||||
|
|
||||||
|
def initialize(page: , current: false, theme: nil, views_prefix: nil)
|
||||||
|
@page = page
|
||||||
|
@current = current
|
||||||
|
@theme = theme
|
||||||
|
@views_prefix = views_prefix
|
||||||
end
|
end
|
||||||
|
|
||||||
%w[first_page prev_page next_page last_page gap].each do |tag|
|
|
||||||
eval <<-DEF, nil, __FILE__, __LINE__ + 1
|
|
||||||
def #{tag}_tag
|
|
||||||
@last = #{tag.classify}.new @template, @options
|
|
||||||
end
|
|
||||||
DEF
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_s #:nodoc:
|
|
||||||
Thread.current[:kaminari_rendering] = true
|
|
||||||
super @window_options.merge paginator: self
|
|
||||||
ensure
|
|
||||||
Thread.current[:kaminari_rendering] = false
|
|
||||||
end
|
|
||||||
|
|
||||||
# delegates view helper methods to @template
|
|
||||||
def method_missing(name, *args, &block)
|
|
||||||
@template.respond_to?(name) ? @template.send(name, *args, &block) : super
|
|
||||||
end
|
|
||||||
private :method_missing
|
|
||||||
|
|
||||||
# Wraps a "page number" and provides some utility methods
|
|
||||||
class PageProxy
|
|
||||||
include Comparable
|
|
||||||
|
|
||||||
def initialize(options, page, last) #:nodoc:
|
|
||||||
@options, @page, @last = options, page, last
|
|
||||||
end
|
|
||||||
|
|
||||||
# the page number
|
|
||||||
def number
|
|
||||||
@page
|
|
||||||
end
|
|
||||||
|
|
||||||
# current page or not
|
|
||||||
def current?
|
def current?
|
||||||
@page == @options[:current_page]
|
page == current
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_page
|
||||||
|
PageProxy.new(page, current_page: current)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_partial_path
|
||||||
|
[ @views_prefix, "kaminari", @theme, self.class.name.demodulize.underscore ].compact.join("/")
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
page.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class FirstPage < Page; end
|
||||||
|
class PrevPage < Page; end
|
||||||
|
class NextPage < Page; end
|
||||||
|
class LastPage < Page; end
|
||||||
|
|
||||||
|
class PageProxy < SimpleDelegator
|
||||||
|
attr_reader :current_page
|
||||||
|
|
||||||
|
def initialize(page, current_page: )
|
||||||
|
super(page.to_i)
|
||||||
|
@current_page = current_page
|
||||||
end
|
end
|
||||||
|
|
||||||
# the first page or not
|
|
||||||
def first?
|
def first?
|
||||||
@page == 1
|
1 == current_page
|
||||||
end
|
end
|
||||||
|
|
||||||
# the last page or not
|
|
||||||
def last?
|
def last?
|
||||||
@page == @options[:total_pages]
|
__getobj__ == current_page
|
||||||
end
|
|
||||||
|
|
||||||
# the previous page or not
|
|
||||||
def prev?
|
|
||||||
@page == @options[:current_page] - 1
|
|
||||||
end
|
|
||||||
|
|
||||||
# the next page or not
|
|
||||||
def next?
|
|
||||||
@page == @options[:current_page] + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
# relationship with the current page
|
|
||||||
def rel
|
|
||||||
if next?
|
|
||||||
'next'
|
|
||||||
elsif prev?
|
|
||||||
'prev'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# within the left outer window or not
|
|
||||||
def left_outer?
|
|
||||||
@page <= @options[:left]
|
|
||||||
end
|
|
||||||
|
|
||||||
# within the right outer window or not
|
|
||||||
def right_outer?
|
|
||||||
@options[:total_pages] - @page < @options[:right]
|
|
||||||
end
|
|
||||||
|
|
||||||
# inside the inner window or not
|
|
||||||
def inside_window?
|
|
||||||
(@options[:current_page] - @page).abs <= @options[:window]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Current page is an isolated gap or not
|
|
||||||
def single_gap?
|
|
||||||
((@page == @options[:current_page] - @options[:window] - 1) && (@page == @options[:left] + 1)) ||
|
|
||||||
((@page == @options[:current_page] + @options[:window] + 1) && (@page == @options[:total_pages] - @options[:right]))
|
|
||||||
end
|
|
||||||
|
|
||||||
# The page number exceeds the range of pages or not
|
|
||||||
def out_of_range?
|
|
||||||
@page > @options[:total_pages]
|
|
||||||
end
|
|
||||||
|
|
||||||
# The last rendered tag was "truncated" or not
|
|
||||||
def was_truncated?
|
|
||||||
@last.is_a? Gap
|
|
||||||
end
|
|
||||||
|
|
||||||
#Should we display the link tag?
|
|
||||||
def display_tag?
|
|
||||||
left_outer? || right_outer? || inside_window? || single_gap?
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_i #:nodoc:
|
|
||||||
number
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_s #:nodoc:
|
|
||||||
number.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
def +(other) #:nodoc:
|
|
||||||
to_i + other.to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
def -(other) #:nodoc:
|
|
||||||
to_i - other.to_i
|
|
||||||
end
|
|
||||||
|
|
||||||
def <=>(other) #:nodoc:
|
|
||||||
to_i <=> other.to_i
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,11 +27,6 @@ module Kaminari
|
||||||
@params.merge! params
|
@params.merge! params
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s(locals = {}) #:nodoc:
|
|
||||||
formats = (@template.respond_to?(:formats) ? @template.formats : Array(@template.params[:format])) + [:html]
|
|
||||||
@template.render partial: partial_path, locals: @options.merge(locals), formats: formats
|
|
||||||
end
|
|
||||||
|
|
||||||
def page_url_for(page)
|
def page_url_for(page)
|
||||||
params = params_for(page)
|
params = params_for(page)
|
||||||
params[:only_path] = true
|
params[:only_path] = true
|
||||||
|
@ -58,60 +53,14 @@ module Kaminari
|
||||||
|
|
||||||
page_params
|
page_params
|
||||||
end
|
end
|
||||||
|
|
||||||
def partial_path
|
|
||||||
[
|
|
||||||
@views_prefix,
|
|
||||||
"kaminari",
|
|
||||||
@theme,
|
|
||||||
self.class.name.demodulize.underscore
|
|
||||||
].compact.join("/")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Tag that contains a link
|
# Tag that contains a link
|
||||||
module Link
|
module Link
|
||||||
# target page number
|
|
||||||
def page
|
|
||||||
raise 'Override page with the actual page value to be a Page.'
|
|
||||||
end
|
|
||||||
# the link's href
|
# the link's href
|
||||||
def url
|
def url
|
||||||
page_url_for page
|
page_url_for page
|
||||||
end
|
end
|
||||||
def to_s(locals = {}) #:nodoc:
|
|
||||||
locals[:url] = url
|
|
||||||
super locals
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# A page
|
|
||||||
class Page < Tag
|
|
||||||
include Link
|
|
||||||
# target page number
|
|
||||||
def page
|
|
||||||
@options[:page]
|
|
||||||
end
|
|
||||||
def to_s(locals = {}) #:nodoc:
|
|
||||||
locals[:page] = page
|
|
||||||
super locals
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Link with page number that appears at the leftmost
|
|
||||||
class FirstPage < Tag
|
|
||||||
include Link
|
|
||||||
def page #:nodoc:
|
|
||||||
1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Link with page number that appears at the rightmost
|
|
||||||
class LastPage < Tag
|
|
||||||
include Link
|
|
||||||
def page #:nodoc:
|
|
||||||
@options[:total_pages]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# The "previous" page of the current page
|
# The "previous" page of the current page
|
||||||
|
|
|
@ -10,6 +10,8 @@ class KaminariTestApp < Rails::Application
|
||||||
config.session_store :cookie_store, key: '_myapp_session'
|
config.session_store :cookie_store, key: '_myapp_session'
|
||||||
config.active_support.deprecation = :log
|
config.active_support.deprecation = :log
|
||||||
config.eager_load = false
|
config.eager_load = false
|
||||||
|
config.consider_all_requests_local = true
|
||||||
|
config.action_dispatch.show_exceptions = false
|
||||||
# Rails.root
|
# Rails.root
|
||||||
config.root = File.dirname(__FILE__)
|
config.root = File.dirname(__FILE__)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue