2016-10-12 05:44:41 +09:00
|
|
|
# frozen_string_literal: true
|
2011-11-21 20:14:03 +09:00
|
|
|
require 'active_support/inflector'
|
|
|
|
require 'kaminari/helpers/tags'
|
2011-02-11 03:45:43 +09:00
|
|
|
|
2011-02-05 23:05:40 +09:00
|
|
|
module Kaminari
|
|
|
|
module Helpers
|
2011-02-27 23:25:16 +09:00
|
|
|
# The main container tag
|
|
|
|
class Paginator < Tag
|
2016-11-23 09:16:04 +09:00
|
|
|
def initialize(template, window: nil, outer_window: nil, left: nil, right: nil, inner_window: nil, **options) #:nodoc:
|
2016-11-23 09:21:23 +09:00
|
|
|
outer_window ||= Kaminari.config.outer_window
|
2016-12-08 11:07:15 +09:00
|
|
|
left ||= Kaminari.config.left
|
|
|
|
right ||= Kaminari.config.right
|
|
|
|
@window_options = {window: window || inner_window || Kaminari.config.window, left: left.zero? ? outer_window : left, right: right.zero? ? outer_window : right}
|
2016-11-23 09:21:23 +09:00
|
|
|
|
2016-12-08 15:58:56 +09:00
|
|
|
@template, @options, @theme, @views_prefix, @last = template, options, options[:theme], options[:views_prefix], nil
|
2013-11-24 01:04:11 +09:00
|
|
|
@window_options.merge! @options
|
2013-12-02 19:00:32 +09:00
|
|
|
@window_options[:current_page] = @options[:current_page] = PageProxy.new(@window_options, @options[:current_page], nil)
|
2013-11-24 01:04:11 +09:00
|
|
|
|
2016-10-03 08:38:52 +09:00
|
|
|
#XXX Using parent template's buffer class for rendering each partial here. This might cause problems if the handler mismatches
|
2016-12-08 11:07:15 +09:00
|
|
|
@output_buffer = if defined?(::ActionView::OutputBuffer)
|
|
|
|
::ActionView::OutputBuffer.new
|
2016-10-04 11:23:48 +09:00
|
|
|
elsif template.instance_variable_get(:@output_buffer)
|
2016-12-08 11:07:15 +09:00
|
|
|
template.instance_variable_get(:@output_buffer).class.new
|
2016-10-04 11:23:48 +09:00
|
|
|
else
|
2016-12-08 11:07:15 +09:00
|
|
|
ActiveSupport::SafeBuffer.new
|
2016-10-04 11:23:48 +09:00
|
|
|
end
|
2011-02-27 23:25:16 +09:00
|
|
|
end
|
|
|
|
|
|
|
|
# render given block as a view template
|
|
|
|
def render(&block)
|
2012-05-25 15:31:53 +09:00
|
|
|
instance_eval(&block) if @options[:total_pages] > 1
|
2011-02-27 23:25:16 +09:00
|
|
|
@output_buffer
|
|
|
|
end
|
|
|
|
|
|
|
|
# enumerate each page providing PageProxy object as the block parameter
|
2011-12-11 23:12:55 +09:00
|
|
|
# Because of performance reason, this doesn't actually enumerate all pages but pages that are seemingly relevant to the paginator.
|
|
|
|
# "Relevant" pages are:
|
|
|
|
# * pages inside the left outer window plus one for showing the gap tag
|
|
|
|
# * pages inside the inner window plus one on the left plus one on the right for showing the gap tags
|
|
|
|
# * pages inside the right outer window plus one for showing the gap tag
|
2011-07-27 10:35:38 -04:00
|
|
|
def each_relevant_page
|
|
|
|
return to_enum(:each_relevant_page) unless block_given?
|
|
|
|
|
2014-03-30 10:42:24 -07:00
|
|
|
relevant_pages(@window_options).each do |page|
|
|
|
|
yield PageProxy.new(@window_options, page, @last)
|
2011-07-27 10:35:38 -04:00
|
|
|
end
|
|
|
|
end
|
2011-12-11 23:12:55 +09:00
|
|
|
alias each_page each_relevant_page
|
|
|
|
|
|
|
|
def relevant_pages(options)
|
2016-12-08 12:40:03 +09:00
|
|
|
left_window_plus_one = [*1..options[:left] + 1]
|
|
|
|
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]
|
2011-12-11 23:12:55 +09:00
|
|
|
|
2016-12-08 10:46:44 +09:00
|
|
|
(left_window_plus_one | inside_window_plus_each_sides | right_window_plus_one).sort.reject {|x| (x < 1) || (x > options[:total_pages])}
|
2011-12-11 23:12:55 +09:00
|
|
|
end
|
|
|
|
private :relevant_pages
|
2011-07-27 10:35:38 -04:00
|
|
|
|
2011-02-27 23:25:16 +09:00
|
|
|
def page_tag(page)
|
2016-11-22 22:16:57 +09:00
|
|
|
@last = Page.new @template, @options.merge(page: page)
|
2011-02-27 23:25:16 +09:00
|
|
|
end
|
|
|
|
|
|
|
|
%w[first_page prev_page next_page last_page gap].each do |tag|
|
2016-11-07 12:45:46 +09:00
|
|
|
eval <<-DEF, nil, __FILE__, __LINE__ + 1
|
2011-02-27 23:25:16 +09:00
|
|
|
def #{tag}_tag
|
|
|
|
@last = #{tag.classify}.new @template, @options
|
|
|
|
end
|
|
|
|
DEF
|
2011-02-16 23:24:31 +09:00
|
|
|
end
|
|
|
|
|
|
|
|
def to_s #:nodoc:
|
2016-11-27 21:48:16 +09:00
|
|
|
Thread.current[:kaminari_rendering] = true
|
2016-11-22 22:16:57 +09:00
|
|
|
super @window_options.merge paginator: self
|
2016-11-27 21:48:16 +09:00
|
|
|
ensure
|
|
|
|
Thread.current[:kaminari_rendering] = false
|
2011-02-06 21:21:13 +09:00
|
|
|
end
|
2011-02-27 23:25:16 +09:00
|
|
|
|
2014-03-15 15:18:54 -07:00
|
|
|
# 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
|
|
|
|
|
2011-02-27 23:25:16 +09:00
|
|
|
# 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?
|
|
|
|
@page == @options[:current_page]
|
|
|
|
end
|
|
|
|
|
|
|
|
# the first page or not
|
|
|
|
def first?
|
|
|
|
@page == 1
|
|
|
|
end
|
|
|
|
|
|
|
|
# the last page or not
|
|
|
|
def last?
|
2012-05-25 15:31:53 +09:00
|
|
|
@page == @options[:total_pages]
|
2011-02-27 23:25:16 +09:00
|
|
|
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
|
|
|
|
|
2016-02-12 15:08:10 +01:00
|
|
|
# relationship with the current page
|
|
|
|
def rel
|
|
|
|
if next?
|
|
|
|
'next'
|
|
|
|
elsif prev?
|
|
|
|
'prev'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-02-27 23:25:16 +09:00
|
|
|
# within the left outer window or not
|
|
|
|
def left_outer?
|
|
|
|
@page <= @options[:left]
|
|
|
|
end
|
|
|
|
|
|
|
|
# within the right outer window or not
|
|
|
|
def right_outer?
|
2012-05-25 15:31:53 +09:00
|
|
|
@options[:total_pages] - @page < @options[:right]
|
2011-02-27 23:25:16 +09:00
|
|
|
end
|
|
|
|
|
|
|
|
# inside the inner window or not
|
|
|
|
def inside_window?
|
2011-02-28 00:17:09 +09:00
|
|
|
(@options[:current_page] - @page).abs <= @options[:window]
|
2011-02-27 23:25:16 +09:00
|
|
|
end
|
|
|
|
|
2016-12-08 12:31:07 +09:00
|
|
|
# Current page is an isolated gap or not
|
2013-02-10 16:44:53 -08:00
|
|
|
def single_gap?
|
2016-12-08 12:26:59 +09:00
|
|
|
((@page == @options[:current_page] - @options[:window] - 1) && (@page == @options[:left] + 1)) ||
|
|
|
|
((@page == @options[:current_page] + @options[:window] + 1) && (@page == @options[:total_pages] - @options[:right]))
|
2013-02-10 16:44:53 -08:00
|
|
|
end
|
|
|
|
|
2016-12-08 12:31:07 +09:00
|
|
|
# The page number exceeds the range of pages or not
|
2014-09-13 19:27:37 -07:00
|
|
|
def out_of_range?
|
|
|
|
@page > @options[:total_pages]
|
|
|
|
end
|
|
|
|
|
2011-02-27 23:25:16 +09:00
|
|
|
# The last rendered tag was "truncated" or not
|
|
|
|
def was_truncated?
|
|
|
|
@last.is_a? Gap
|
|
|
|
end
|
|
|
|
|
2013-02-10 16:44:53 -08:00
|
|
|
#Should we display the link tag?
|
|
|
|
def display_tag?
|
|
|
|
left_outer? || right_outer? || inside_window? || single_gap?
|
|
|
|
end
|
|
|
|
|
2016-12-08 12:31:07 +09:00
|
|
|
def to_i #:nodoc:
|
2011-02-27 23:25:16 +09:00
|
|
|
number
|
|
|
|
end
|
|
|
|
|
2016-12-08 12:31:07 +09:00
|
|
|
def to_s #:nodoc:
|
2011-02-27 23:25:16 +09:00
|
|
|
number.to_s
|
|
|
|
end
|
|
|
|
|
2016-12-08 12:31:07 +09:00
|
|
|
def +(other) #:nodoc:
|
2011-02-28 00:17:09 +09:00
|
|
|
to_i + other.to_i
|
|
|
|
end
|
|
|
|
|
2016-12-08 12:31:07 +09:00
|
|
|
def -(other) #:nodoc:
|
2011-02-28 00:17:09 +09:00
|
|
|
to_i - other.to_i
|
|
|
|
end
|
|
|
|
|
2016-12-08 12:31:07 +09:00
|
|
|
def <=>(other) #:nodoc:
|
2011-02-27 23:25:16 +09:00
|
|
|
to_i <=> other.to_i
|
|
|
|
end
|
|
|
|
end
|
2011-02-05 23:09:07 +09:00
|
|
|
end
|
2011-02-05 23:05:40 +09:00
|
|
|
end
|
|
|
|
end
|