mjfreshyfresh-leaf 0.0.1

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.
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2010 Peter Hellberg
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,53 @@
1
+ = Leaf
2
+
3
+ A _really_ simple pagination library, heavily based on the agnostic branch of
4
+ {will_paginate}[http://github.com/mislav/will_paginate/tree/agnostic].
5
+
6
+ = Description
7
+
8
+ Leaf supports pagination for collections responding to +total_pages+,
9
+ +per_page+, +previous_page+ and +total_entries+ in Sinatra views out of the box.
10
+
11
+ It currently supports two renderers: +Leaf::ViewHelpers::LinkRenderer+
12
+ and +Leaf::ViewHelpers::ListRenderer+
13
+
14
+ == Installation
15
+
16
+ gem install leaf
17
+
18
+ == Example usage
19
+
20
+ require 'rubygems'
21
+ require 'sinatra'
22
+ require 'leaf'
23
+
24
+ include Leaf::ViewHelpers::Base
25
+
26
+ # Needed to paginate any array
27
+ # you’ll probably use something else.
28
+ require 'leaf/array'
29
+
30
+ get '/' do
31
+ page = (params[:page]) ? params[:page] : 1
32
+ array = ('a'..'z').to_a
33
+
34
+ haml :index, :locals => {
35
+ :collection => array.paginate({
36
+ :page => page,
37
+ :per_page => 5
38
+ })
39
+ }
40
+ end
41
+
42
+ __END__
43
+ @@ index
44
+ = leaf(collection, :renderer => Leaf::ViewHelpers::ListRenderer)
45
+ %ul
46
+ - collection.each do |letter|
47
+ %li= letter
48
+
49
+ == Authors and credits
50
+
51
+ Leaf is based on {will_paginate}[http://github.com/mislav/will_paginate/] which
52
+ was originally written by PJ Hyett, who later handed over development to Mislav
53
+ Marohnić. (The library was completely rewritten since then.)
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ gem 'rdoc' # Required on Mac OS X to get a “working” rdoc version
3
+ require 'rake/rdoctask'
4
+
5
+ load 'spec/tasks.rake'
6
+
7
+ desc 'Default: run specs.'
8
+ task :default => :spec
9
+
10
+ desc 'Generate RDoc documentation for the leaf gem.'
11
+ Rake::RDocTask.new(:rdoc) do |rdoc|
12
+ rdoc.rdoc_files.include('README.rdoc', 'MIT-LICENSE').
13
+ include('lib/**/*.rb').
14
+ exclude('lib/leaf/finders/sequel.rb').
15
+ exclude('lib/leaf/view_helpers/sinatra.rb').
16
+ exclude('lib/leaf/core_ext.rb').
17
+ exclude('lib/leaf/version.rb')
18
+
19
+ rdoc.main = "README.rdoc" # page to start on
20
+ rdoc.title = "leaf documentation"
21
+
22
+ rdoc.rdoc_dir = 'doc' # rdoc output folder
23
+ rdoc.options << '--inline-source' << '--charset=UTF-8' << '--format=darkfish'
24
+ rdoc.options << '--main=README.rdoc'
25
+ rdoc.options << '--webcvs=http://github.com/c7/leaf/tree/master/'
26
+ end
@@ -0,0 +1,15 @@
1
+ # = Leafing through the pages!
2
+ #
3
+ # First read about Leaf::Finders::Base, then see
4
+ # Leaf::ViewHelpers. The magical array you're handling in-between is
5
+ # Leaf::Collection.
6
+ #
7
+ # Happy paginating!
8
+ module Leaf
9
+ require 'leaf/version'
10
+
11
+ # Load the helpers for Sinatra
12
+ if defined?(Sinatra)
13
+ require 'leaf/view_helpers/sinatra'
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ require 'leaf/collection'
2
+
3
+ class Array
4
+ # Paginates a static array (extracting a subset of it). The result is a
5
+ # Leaf::Collection instance, which is an array with a few more
6
+ # properties about its paginated state.
7
+ #
8
+ # Parameters:
9
+ # * <tt>:page</tt> - current page, defaults to 1
10
+ # * <tt>:per_page</tt> - limit of items per page, defaults to 30
11
+ # * <tt>:total_entries</tt> - total number of items in the array, defaults to
12
+ # <tt>array.length</tt> (obviously)
13
+ #
14
+ # Example:
15
+ # arr = ['a', 'b', 'c', 'd', 'e']
16
+ # paged = arr.paginate(:per_page => 2) #-> ['a', 'b']
17
+ # paged.total_entries #-> 5
18
+ # arr.paginate(:page => 2, :per_page => 2) #-> ['c', 'd']
19
+ # arr.paginate(:page => 3, :per_page => 2) #-> ['e']
20
+ #
21
+ # This method was originally {suggested by Desi
22
+ # McAdam}[http://www.desimcadam.com/archives/8]
23
+ def paginate(options = {})
24
+ raise ArgumentError, "parameter hash expected (got #{options.inspect})" unless Hash === options
25
+ Leaf::Collection.create options[:page] || 1,
26
+ options[:per_page] || 30,
27
+ options[:total_entries] || self.length do |pager|
28
+ pager.replace self[pager.offset, pager.per_page].to_a
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,100 @@
1
+ module Leaf
2
+ # = Invalid page number error
3
+ # This is an ArgumentError raised in case a page was requested that is either
4
+ # zero or negative number. You should decide how do deal with such errors in
5
+ # the controller.
6
+ class InvalidPage < ArgumentError
7
+ def initialize(page, page_num)
8
+ super "#{page.inspect} given as value, which translates to '#{page_num}' as page number"
9
+ end
10
+ end
11
+
12
+ # = The key to pagination
13
+ # Arrays returned from paginating finds are, in fact, instances of this little
14
+ # class. You may think of Leaf::Collection as an ordinary array with
15
+ # some extra properties. Those properties are used by view helpers to generate
16
+ # correct page links.
17
+ #
18
+ # gem 'leaf'
19
+ # require 'leaf/collection'
20
+ #
21
+ # # now use Leaf::Collection directly or subclass it
22
+ class Collection < Array
23
+ attr_reader :current_page, :per_page, :total_entries, :total_pages
24
+
25
+ # Arguments to the constructor are the current page number, per-page limit
26
+ # and the total number of entries. The last argument is optional because it
27
+ # is best to do lazy counting; in other words, count *conditionally* after
28
+ # populating the collection using the +replace+ method.
29
+ def initialize(page, per_page, total = nil)
30
+ @current_page = page.to_i
31
+ raise InvalidPage.new(page, @current_page) if @current_page < 1
32
+ @per_page = per_page.to_i
33
+ raise ArgumentError, "`per_page` setting cannot be less than 1 (#{@per_page} given)" if @per_page < 1
34
+
35
+ self.total_entries = total if total
36
+ end
37
+
38
+ # Just like +new+, but yields the object after instantiation and returns it
39
+ # afterwards. This is very useful for manual pagination:
40
+ def self.create(page, per_page, total = nil, &block)
41
+ pager = new(page, per_page, total)
42
+ yield pager
43
+ pager
44
+ end
45
+
46
+ # Helper method that is true when someone tries to fetch a page with a
47
+ # larger number than the last page. Can be used in combination with flashes
48
+ # and redirecting.
49
+ def out_of_bounds?
50
+ current_page > total_pages
51
+ end
52
+
53
+ # Current offset of the paginated collection. If we're on the first page,
54
+ # it is always 0. If we're on the 2nd page and there are 30 entries per page,
55
+ # the offset is 30. This property is useful if you want to render ordinals
56
+ # besides your records: simply start with offset + 1.
57
+ def offset
58
+ (current_page - 1) * per_page
59
+ end
60
+
61
+ # current_page - 1 or nil if there is no previous page
62
+ def previous_page
63
+ current_page > 1 ? (current_page - 1) : nil
64
+ end
65
+
66
+ # current_page + 1 or nil if there is no next page
67
+ def next_page
68
+ current_page < total_pages ? (current_page + 1) : nil
69
+ end
70
+
71
+ def total_entries=(number)
72
+ @total_entries = number.to_i
73
+ @total_pages = (@total_entries / per_page.to_f).ceil
74
+ end
75
+
76
+ # This is a magic wrapper for the original Array#replace method. It serves
77
+ # for populating the paginated collection after initialization.
78
+ #
79
+ # Why magic? Because it tries to guess the total number of entries judging
80
+ # by the size of given array. If it is shorter than +per_page+ limit, then we
81
+ # know we're on the last page. This trick is very useful for avoiding
82
+ # unnecessary hits to the database to do the counting after we fetched the
83
+ # data for the current page.
84
+ #
85
+ # However, after using +replace+ you should always test the value of
86
+ # +total_entries+ and set it to a proper value if it's +nil+. See the example
87
+ # in +create+.
88
+ def replace(array)
89
+ result = super
90
+
91
+ # The collection is shorter then page limit? Rejoice, because
92
+ # then we know that we are on the last page!
93
+ if total_entries.nil? and length < per_page and (current_page == 1 or length > 0)
94
+ self.total_entries = offset + length
95
+ end
96
+
97
+ result
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,69 @@
1
+ require 'set'
2
+ require 'leaf/array'
3
+
4
+ # helper to check for method existance in ruby 1.8- and 1.9-compatible way
5
+ # because `methods`, `instance_methods` and others return strings in 1.8 and symbols in 1.9
6
+ #
7
+ # ['foo', 'bar'].include_method?(:foo) # => true
8
+ class Array
9
+ def include_method?(name)
10
+ name = name.to_sym
11
+ !!(find { |item| item.to_sym == name })
12
+ end
13
+ end
14
+
15
+ ## everything below copied from ActiveSupport so we don't depend on it ##
16
+
17
+ unless Hash.instance_methods.include_method? :except
18
+ Hash.class_eval do
19
+ # Returns a new hash without the given keys.
20
+ def except(*keys)
21
+ rejected = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
22
+ reject { |key,| rejected.include?(key) }
23
+ end
24
+
25
+ # Replaces the hash without only the given keys.
26
+ def except!(*keys)
27
+ replace(except(*keys))
28
+ end
29
+ end
30
+ end
31
+
32
+ unless Hash.instance_methods.include_method? :slice
33
+ Hash.class_eval do
34
+ # Returns a new hash with only the given keys.
35
+ def slice(*keys)
36
+ allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
37
+ reject { |key,| !allowed.include?(key) }
38
+ end
39
+
40
+ # Replaces the hash with only the given keys.
41
+ def slice!(*keys)
42
+ replace(slice(*keys))
43
+ end
44
+ end
45
+ end
46
+
47
+ unless String.instance_methods.include_method? :constantize
48
+ String.class_eval do
49
+ def constantize
50
+ unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ self
51
+ raise NameError, "#{self.inspect} is not a valid constant name!"
52
+ end
53
+
54
+ Object.module_eval("::#{$1}", __FILE__, __LINE__)
55
+ end
56
+ end
57
+ end
58
+
59
+ unless String.instance_methods.include_method? :underscore
60
+ String.class_eval do
61
+ def underscore
62
+ self.to_s.gsub(/::/, '/').
63
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
64
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
65
+ tr("-", "_").
66
+ downcase
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,9 @@
1
+ require 'leaf/core_ext'
2
+
3
+ module Leaf
4
+ # Database logic for different ORMs
5
+ #
6
+ # See Leaf::Finders::Base
7
+ module Finders
8
+ end
9
+ end
@@ -0,0 +1,82 @@
1
+ require 'leaf/core_ext'
2
+
3
+ module Leaf
4
+ module Finders
5
+ # = Database-agnostic finder module
6
+ #
7
+ # Out of the box, leaf supports hooking in the Sequel ORM
8
+ module Base
9
+ def per_page
10
+ @per_page ||= 30
11
+ end
12
+
13
+ def per_page=(limit)
14
+ @per_page = limit.to_i
15
+ end
16
+
17
+ # This is the main paginating finder.
18
+ #
19
+ # == Special parameters for paginating finders
20
+ # * <tt>:page</tt> -- REQUIRED, but defaults to 1 if false or nil
21
+ # * <tt>:per_page</tt> -- defaults to <tt>CurrentModel.per_page</tt> (which is 30 if not overridden)
22
+ # * <tt>:total_entries</tt> -- use only if you manually count total entries
23
+ # * <tt>:count</tt> -- additional options that are passed on to +count+
24
+ # * <tt>:finder</tt> -- name of the finder method to use (default: "find")
25
+ #
26
+ # All other options (+conditions+, +order+, ...) are forwarded to +find+
27
+ # and +count+ calls.
28
+ def paginate(*args, &block)
29
+ options = args.pop
30
+ page, per_page, total_entries = leaf_parse_options(options)
31
+
32
+ Leaf::Collection.create(page, per_page, total_entries) do |pager|
33
+ query_options = options.except :page, :per_page, :total_entries
34
+ wp_query(query_options, pager, args, &block)
35
+ end
36
+ end
37
+
38
+ # Iterates through all records by loading one page at a time. This is useful
39
+ # for migrations or any other use case where you don't want to load all the
40
+ # records in memory at once.
41
+ #
42
+ # It uses +paginate+ internally; therefore it accepts all of its options.
43
+ # You can specify a starting page with <tt>:page</tt> (default is 1). Default
44
+ # <tt>:order</tt> is <tt>"id"</tt>, override if necessary.
45
+ #
46
+ # {Jamis Buck describes this}[http://weblog.jamisbuck.org/2007/4/6/faking-cursors-in-activerecord]
47
+ # and also uses a more efficient way for MySQL.
48
+ def paginated_each(options = {}, &block)
49
+ options = { :order => 'id', :page => 1 }.merge options
50
+ options[:page] = options[:page].to_i
51
+ options[:total_entries] = 0 # skip the individual count queries
52
+ total = 0
53
+
54
+ begin
55
+ collection = paginate(options)
56
+ total += collection.each(&block).size
57
+ options[:page] += 1
58
+ end until collection.size < collection.per_page
59
+
60
+ total
61
+ end
62
+
63
+ protected
64
+
65
+ def leaf_parse_options(options)
66
+ raise ArgumentError, 'parameter hash expected' unless Hash === options
67
+ raise ArgumentError, ':page parameter required' unless options.key? :page
68
+
69
+ if options[:count] and options[:total_entries]
70
+ raise ArgumentError, ':count and :total_entries are mutually exclusive'
71
+ end
72
+
73
+ page = options[:page] || 1
74
+ per_page = options[:per_page] || self.per_page
75
+ total = options[:total_entries]
76
+
77
+ return [page, per_page, total]
78
+ end
79
+
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,23 @@
1
+ require 'sequel'
2
+ require 'sequel/extensions/pagination'
3
+ require 'leaf/core_ext'
4
+
5
+ existing_methods = Sequel::Dataset::Pagination.instance_methods
6
+
7
+ Sequel::Dataset::Pagination.module_eval do
8
+ # it should quack like a Leaf::Collection
9
+
10
+ alias :total_pages :page_count unless existing_methods.include_method? :total_pages
11
+ alias :per_page :page_size unless existing_methods.include_method? :per_page
12
+ alias :previous_page :prev_page unless existing_methods.include_method? :previous_page
13
+ alias :total_entries :pagination_record_count unless existing_methods.include_method? :total_entries
14
+
15
+ def out_of_bounds?
16
+ current_page > total_pages
17
+ end
18
+
19
+ # Current offset of the paginated collection
20
+ def offset
21
+ (current_page - 1) * per_page
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ module Leaf
2
+ module VERSION
3
+ MAJOR = 0
4
+ MINOR = 0
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ module Leaf
2
+ # = Leaf view helpers
3
+ #
4
+ # The main view helper is +leaf+. It renders the pagination links
5
+ # for the given collection.
6
+ #
7
+ # Read more in Leaf::ViewHelpers::Base
8
+ module ViewHelpers
9
+ # ==== Global options for helpers
10
+ #
11
+ # Options for pagination helpers are optional and get their default values
12
+ # from the Leaf::ViewHelpers.pagination_options hash. You can write
13
+ # to this hash to override default options on the global level:
14
+ #
15
+ # Leaf::ViewHelpers.pagination_options[:previous_label] = 'Previous page'
16
+ def self.pagination_options() @pagination_options; end
17
+ # Overrides the default +pagination_options+
18
+ def self.pagination_options=(value) @pagination_options = value; end
19
+
20
+ self.pagination_options = {
21
+ :class => 'pagination',
22
+ :previous_label => '&#8592; Previous',
23
+ :next_label => 'Next &#8594;',
24
+ :inner_window => 4, # links around the current page
25
+ :outer_window => 1, # links around beginning and end
26
+ :separator => ' ', # single space is friendly to spiders and non-graphic browsers
27
+ :param_name => :page,
28
+ :params => nil,
29
+ :renderer => 'Leaf::ViewHelpers::LinkRenderer',
30
+ :page_links => true,
31
+ :container => true
32
+ }
33
+ end
34
+ end
@@ -0,0 +1,60 @@
1
+ require 'leaf/core_ext'
2
+ require 'leaf/view_helpers'
3
+
4
+ module Leaf
5
+ module ViewHelpers
6
+ # = The main view helpers module
7
+ #
8
+ # This is the base module which provides the +leaf+ view helper.
9
+ module Base
10
+ # Renders Digg/Flickr-style pagination for a Leaf::Collection object. Nil is
11
+ # returned if there is only one page in total; pagination links aren't needed in that case.
12
+ #
13
+ # ==== Options
14
+ # * <tt>:class</tt> -- CSS class name for the generated DIV (default: "pagination")
15
+ # * <tt>:previous_label</tt> -- default: "« Previous"
16
+ # * <tt>:next_label</tt> -- default: "Next »"
17
+ # * <tt>:inner_window</tt> -- how many links are shown around the current page (default: 4)
18
+ # * <tt>:outer_window</tt> -- how many links are around the first and the last page (default: 1)
19
+ # * <tt>:separator</tt> -- string separator for page HTML elements (default: single space)
20
+ # * <tt>:param_name</tt> -- parameter name for page number in URLs (default: <tt>:page</tt>)
21
+ # * <tt>:params</tt> -- additional parameters when generating pagination links
22
+ # (eg. <tt>:controller => "foo", :action => nil</tt>)
23
+ # * <tt>:renderer</tt> -- class name, class or instance of a link renderer (default:
24
+ # <tt>Leaf::LinkRenderer</tt>)
25
+ # * <tt>:page_links</tt> -- when false, only previous/next links are rendered (default: true)
26
+ # * <tt>:container</tt> -- toggles rendering of the DIV container for pagination links, set to
27
+ # false only when you are rendering your own pagination markup (default: true)
28
+ # * <tt>:id</tt> -- HTML ID for the container (default: nil). Pass +true+ to have the ID
29
+ # automatically generated from the class name of objects in collection: for example, paginating
30
+ # ArticleComment models would yield an ID of "article_comments_pagination".
31
+ #
32
+ # All options beside listed ones are passed as HTML attributes to the container
33
+ # element for pagination links (the DIV). For example:
34
+ #
35
+ # <%= leaf @posts, :id => 'leaf_posts' %>
36
+ #
37
+ # ... will result in:
38
+ #
39
+ # <div class="pagination" id="leaf_posts"> ... </div>
40
+ #
41
+ def leaf(collection, options = {})
42
+ # early exit if there is nothing to render
43
+ return nil unless collection.total_pages > 1
44
+
45
+ options = Leaf::ViewHelpers.pagination_options.merge(options)
46
+
47
+ # get the renderer instance
48
+ renderer = case options[:renderer]
49
+ when String then options[:renderer].constantize.new
50
+ when Class then options[:renderer].new
51
+ else options[:renderer]
52
+ end
53
+
54
+ # render HTML for pagination
55
+ renderer.prepare collection, options, self
56
+ renderer.to_html
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,129 @@
1
+ require 'leaf/core_ext'
2
+ require 'leaf/view_helpers/link_renderer_base'
3
+
4
+ module Leaf
5
+ module ViewHelpers
6
+ # This class does the heavy lifting of actually building the pagination
7
+ # links. It is used by +leaf+ helper internally.
8
+ class LinkRenderer < LinkRendererBase
9
+
10
+ # * +collection+ is a Leaf::Collection instance or any other object
11
+ # that conforms to that API
12
+ # * +options+ are forwarded from +leaf+ view helper
13
+ # * +template+ is the reference to the template being rendered
14
+ def prepare(collection, options, template)
15
+ super(collection, options)
16
+ @template = template
17
+ @container_attributes = @base_url_params = nil
18
+ end
19
+
20
+ # Process it! This method returns the complete HTML string which contains
21
+ # pagination links. Feel free to subclass LinkRenderer and change this
22
+ # method as you see fit.
23
+ def to_html
24
+ html = pagination.map do |item|
25
+ item.is_a?(Fixnum) ?
26
+ page_number(item) :
27
+ send(item)
28
+ end.join(@options[:separator])
29
+
30
+ @options[:container] ? html_container(html) : html
31
+ end
32
+
33
+ # Returns the subset of +options+ this instance was initialized with that
34
+ # represent HTML attributes for the container element of pagination links.
35
+ def container_attributes
36
+ @container_attributes ||= begin
37
+ attributes = @options.except *(Leaf::ViewHelpers.pagination_options.keys - [:class])
38
+ # pagination of Post models will have the ID of "posts_pagination"
39
+ if @options[:container] and @options[:id] === true
40
+ attributes[:id] = @collection.first.class.name.underscore.pluralize + '_pagination'
41
+ end
42
+ attributes
43
+ end
44
+ end
45
+
46
+ protected
47
+
48
+ def page_number(page)
49
+ unless page == current_page
50
+ link(page, page, :rel => rel_value(page))
51
+ else
52
+ tag(:em, page)
53
+ end
54
+ end
55
+
56
+ def gap
57
+ '<span class="gap">&hellip;</span>'
58
+ end
59
+
60
+ def previous_page
61
+ previous_or_next_page(@collection.previous_page, @options[:previous_label], 'previous_page')
62
+ end
63
+
64
+ def next_page
65
+ previous_or_next_page(@collection.next_page, @options[:next_label], 'next_page')
66
+ end
67
+
68
+ def previous_or_next_page(page, text, classname)
69
+ if page
70
+ link(text, page, :class => classname)
71
+ else
72
+ tag(:span, text, :class => classname + ' disabled')
73
+ end
74
+ end
75
+
76
+ def html_container(html)
77
+ tag(:div, html, container_attributes)
78
+ end
79
+
80
+ # Returns URL params for +page_link_or_span+, taking the current GET params
81
+ # and <tt>:params</tt> option into account.
82
+ def url(page)
83
+ raise NotImplementedError
84
+ end
85
+
86
+ private
87
+
88
+ def link(text, target, attributes = {})
89
+ if target.is_a? Fixnum
90
+ attributes[:rel] = rel_value(target)
91
+ target = url(target)
92
+ end
93
+ attributes[:href] = target
94
+ tag(:a, text, attributes)
95
+ end
96
+
97
+ def tag(name, value, attributes = {})
98
+ string_attributes = attributes.inject('') do |attrs, pair|
99
+ unless pair.last.nil?
100
+ attrs << %( #{pair.first}="#{Rack::Utils.escape_html(pair.last.to_s)}")
101
+ end
102
+ attrs
103
+ end
104
+ "<#{name}#{string_attributes}>#{value}</#{name}>"
105
+ end
106
+
107
+ def rel_value(page)
108
+ case page
109
+ when @collection.previous_page; 'prev' + (page == 1 ? ' start' : '')
110
+ when @collection.next_page; 'next'
111
+ when 1; 'start'
112
+ end
113
+ end
114
+
115
+ def symbolized_update(target, other)
116
+ other.each do |key, value|
117
+ key = key.to_sym
118
+ existing = target[key]
119
+
120
+ if value.is_a?(Hash) and (existing.is_a?(Hash) or existing.nil?)
121
+ symbolized_update(existing || (target[key] = {}), value)
122
+ else
123
+ target[key] = value
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,83 @@
1
+ require 'leaf/view_helpers'
2
+
3
+ module Leaf
4
+ module ViewHelpers
5
+ # This class does the heavy lifting of actually building the pagination
6
+ # links. It is used by +leaf+ helper internally.
7
+ class LinkRendererBase
8
+
9
+ # * +collection+ is a Leaf::Collection instance or any other object
10
+ # that conforms to that API
11
+ # * +options+ are forwarded from +leaf+ view helper
12
+ def prepare(collection, options)
13
+ @collection = collection
14
+ @options = options
15
+
16
+ # reset values in case we're re-using this instance
17
+ @total_pages = @param_name = nil
18
+ end
19
+
20
+ def pagination
21
+ items = @options[:page_links] ? windowed_page_numbers : []
22
+ items.unshift :previous_page
23
+ items.push :next_page
24
+ end
25
+
26
+ protected
27
+
28
+ # Calculates visible page numbers using the <tt>:inner_window</tt> and
29
+ # <tt>:outer_window</tt> options.
30
+ def windowed_page_numbers
31
+ inner_window, outer_window = @options[:inner_window].to_i, @options[:outer_window].to_i
32
+ window_from = current_page - inner_window
33
+ window_to = current_page + inner_window
34
+
35
+ # adjust lower or upper limit if other is out of bounds
36
+ if window_to > total_pages
37
+ window_from -= window_to - total_pages
38
+ window_to = total_pages
39
+ end
40
+ if window_from < 1
41
+ window_to += 1 - window_from
42
+ window_from = 1
43
+ window_to = total_pages if window_to > total_pages
44
+ end
45
+
46
+ # these are always visible
47
+ middle = window_from..window_to
48
+
49
+ # left window
50
+ if outer_window + 3 < middle.first # there's a gap
51
+ left = (1..(outer_window + 1)).to_a
52
+ left << :gap
53
+ else # runs into visible pages
54
+ left = 1...middle.first
55
+ end
56
+
57
+ # right window
58
+ if total_pages - outer_window - 2 > middle.last # again, gap
59
+ right = ((total_pages - outer_window)..total_pages).to_a
60
+ right.unshift :gap
61
+ else # runs into visible pages
62
+ right = (middle.last + 1)..total_pages
63
+ end
64
+
65
+ left.to_a + middle.to_a + right.to_a
66
+ end
67
+
68
+ private
69
+
70
+ def current_page
71
+ @collection.current_page
72
+ end
73
+
74
+ def total_pages
75
+ @collection.total_pages
76
+ end
77
+
78
+ def param_name
79
+ @param_name ||= @options[:param_name].to_s
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,39 @@
1
+ require 'leaf/view_helpers/link_renderer'
2
+
3
+ module Leaf
4
+ module ViewHelpers
5
+ class ListRenderer < LinkRenderer
6
+ def to_html
7
+ html = pagination.map do |item|
8
+ "\n " + tag(:li, (item.is_a?(Fixnum) ?
9
+ page_number(item) :
10
+ send(item)))
11
+ end.join(@options[:separator])
12
+
13
+ @options[:container] ? html_container(html) : html
14
+ end
15
+
16
+ def previous_or_next_page(page, text, classname)
17
+ if page
18
+ link(tag(:span, text), page, :class => classname)
19
+ else
20
+ tag(:span, tag(:span, text), :class => classname + ' disabled')
21
+ end
22
+ end
23
+
24
+ def html_container(html)
25
+ tag(:div, "\n " +
26
+ tag(:ul, html + "\n ") + "\n", container_attributes) + "\n"
27
+ end
28
+
29
+ private
30
+ def page_number(page)
31
+ unless page == current_page
32
+ link(tag(:span, page), page, :rel => rel_value(page))
33
+ else
34
+ tag(:em, tag(:span, page))
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,20 @@
1
+ require 'leaf/view_helpers/base'
2
+ require 'leaf/view_helpers/link_renderer'
3
+ require 'leaf/view_helpers/list_renderer'
4
+
5
+ Leaf::ViewHelpers::LinkRenderer.class_eval do
6
+ protected
7
+ def url(page)
8
+ url = @template.request.url
9
+ if page == 1
10
+ # strip out page param and trailing ? and & if they exists
11
+ url.gsub(/(\?|\&)#{@options[:param_name]}=[0-9]+/, '').gsub(/\?$/, '').gsub(/\&$/, '')
12
+ else
13
+ if url =~ /(\?|\&)#{@options[:param_name]}=[0-9]+/
14
+ url.gsub(/#{@options[:param_name]}=[0-9]+/, "#{@options[:param_name]}=#{page}").gsub(/\&+/, '&')
15
+ else
16
+ (url =~ /\?/) ? url + "&#{@options[:param_name]}=#{page}" : url + "?#{@options[:param_name]}=#{page}"
17
+ end
18
+ end
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mjfreshyfresh-leaf
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Peter Hellberg
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-09-13 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rack
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 2
30
+ - 0
31
+ version: 1.2.0
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: A really simple pagination library, heavily based on the agnostic branch of will_paginate
35
+ email: peter@c7.se
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - README.rdoc
42
+ - MIT-LICENSE
43
+ files:
44
+ - lib/leaf/array.rb
45
+ - lib/leaf/collection.rb
46
+ - lib/leaf/core_ext.rb
47
+ - lib/leaf/finders/base.rb
48
+ - lib/leaf/finders/sequel.rb
49
+ - lib/leaf/finders.rb
50
+ - lib/leaf/version.rb
51
+ - lib/leaf/view_helpers/base.rb
52
+ - lib/leaf/view_helpers/link_renderer.rb
53
+ - lib/leaf/view_helpers/link_renderer_base.rb
54
+ - lib/leaf/view_helpers/list_renderer.rb
55
+ - lib/leaf/view_helpers/sinatra.rb
56
+ - lib/leaf/view_helpers.rb
57
+ - lib/leaf.rb
58
+ - MIT-LICENSE
59
+ - Rakefile
60
+ - README.rdoc
61
+ has_rdoc: true
62
+ homepage: http://c7.github.com/leaf/
63
+ licenses:
64
+ - MIT-LICENSE
65
+ post_install_message:
66
+ rdoc_options:
67
+ - --main
68
+ - README.rdoc
69
+ - --charset=UTF-8
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ requirements: []
87
+
88
+ rubyforge_project: leaf
89
+ rubygems_version: 1.3.6
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: Simple pagination library
93
+ test_files: []
94
+