2011-11-21 20:14:03 +09:00
require 'active_support/inflector'
2016-04-15 10:23:54 +09:00
require 'active_support/deprecation'
2011-11-21 20:14:03 +09:00
require 'action_view'
require 'action_view/log_subscriber'
2011-05-03 22:50:35 +09:00
require 'action_view/context'
2011-11-21 20:14:03 +09:00
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
2011-05-03 22:50:35 +09:00
# so that this instance can actually "render"
include :: ActionView :: Context
2011-02-16 23:24:31 +09:00
def initialize ( template , options ) #:nodoc:
2016-04-15 04:00:20 +09:00
ActiveSupport :: Deprecation . warn 'num_pages is deprecated and will be removed in Kaminari 1.0. Please use total_pages instead.' if options . has_key? :num_pages
2014-11-05 20:58:20 -08:00
options [ :num_pages ] || = options [ :total_pages ]
2013-11-24 00:39:31 +09:00
2011-02-27 23:25:16 +09:00
@window_options = { } . tap do | h |
2011-04-21 15:49:45 +09:00
h [ :window ] = options . delete ( :window ) || options . delete ( :inner_window ) || Kaminari . config . window
outer_window = options . delete ( :outer_window ) || Kaminari . config . outer_window
h [ :left ] = options . delete ( :left ) || Kaminari . config . left
h [ :left ] = outer_window if h [ :left ] == 0
h [ :right ] = options . delete ( :right ) || Kaminari . config . right
h [ :right ] = outer_window if h [ :right ] == 0
2011-02-27 23:25:16 +09:00
end
2011-02-27 23:14:32 +09:00
@template , @options = template , options
2014-06-10 09:01:55 -07:00
@theme = @options [ :theme ]
2014-05-14 12:50:56 +10:00
@views_prefix = @options [ :views_prefix ]
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
2012-06-20 13:25:14 +09:00
@last = nil
2011-05-03 22:50:35 +09:00
# initialize the output_buffer for Context
2011-02-27 23:25:16 +09:00
@output_buffer = ActionView :: OutputBuffer . new
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 )
left_window_plus_one = 1 . upto ( options [ :left ] + 1 ) . to_a
2012-05-25 15:31:53 +09:00
right_window_plus_one = ( options [ :total_pages ] - options [ :right ] ) . upto ( options [ :total_pages ] ) . to_a
2011-12-11 23:12:55 +09:00
inside_window_plus_each_sides = ( options [ :current_page ] - options [ :window ] - 1 ) . upto ( options [ :current_page ] + options [ :window ] + 1 ) . to_a
2012-05-25 15:31:53 +09:00
( left_window_plus_one + inside_window_plus_each_sides + right_window_plus_one ) . uniq . 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 )
@last = Page . new @template , @options . merge ( :page = > page )
end
%w[ first_page prev_page next_page last_page gap ] . each do | tag |
eval <<-DEF
def #{tag}_tag
@last = #{tag.classify}.new @template, @options
end
DEF
2011-02-16 23:24:31 +09:00
end
def to_s #:nodoc:
2011-04-25 15:53:43 +09:00
subscriber = ActionView :: LogSubscriber . log_subscribers . detect { | ls | ls . is_a? ActionView :: LogSubscriber }
2013-03-15 10:53:25 -05:00
# There is a logging subscriber
# and we don't want it to log render_partial
# It is threadsafe, but might not repress logging
# consistently in a high-load environment
if subscriber
2013-05-13 23:49:32 +09:00
unless defined? subscriber . render_partial_with_logging
class << subscriber
2013-03-15 10:53:25 -05:00
alias_method :render_partial_with_logging , :render_partial
attr_accessor :render_without_logging
# ugly hack to make a renderer where
# we can turn logging on or off
def render_partial ( event )
render_partial_with_logging ( event ) unless render_without_logging
end
end
end
2011-02-06 21:21:13 +09:00
2013-03-15 10:53:25 -05:00
subscriber . render_without_logging = true
2013-11-24 01:04:11 +09:00
ret = super @window_options . merge :paginator = > self
2013-03-15 10:53:25 -05:00
subscriber . render_without_logging = false
2011-04-25 15:53:43 +09:00
2013-03-15 10:53:25 -05:00
ret
else
2013-11-24 01:04:11 +09:00
super @window_options . merge :paginator = > self
2011-02-06 21:21:13 +09:00
end
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
2013-02-10 16:44:53 -08:00
def single_gap?
2015-08-01 20:12:41 +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
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
def to_i
number
end
def to_s
number . to_s
end
2011-02-28 00:17:09 +09:00
def + ( other )
to_i + other . to_i
end
def - ( other )
to_i - other . to_i
end
2011-02-27 23:25:16 +09:00
def <=> ( other )
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