pagy 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b23ad1b8bfd60d555fd55e0b5534c34b29055447c41116454f73892ffc7eef73
4
+ data.tar.gz: 0a8d532508344459576ab5d3c89e772ef0ee626cd3671d56fa21b611815f8d11
5
+ SHA512:
6
+ metadata.gz: d035e9a3319e63353dd743ef0da6c05b995f5f66c5effea233cdecb52bae17bee7f50730a18ed4ccda818b0e29b52ab79db48e37db9f7dfe9c719908c6ebd1b8
7
+ data.tar.gz: d487d610feef6697c625677d4332b474a3f8876a434edfcefa321c371838ef6552ad7bc246cbcb0a5340dc55302d4d9f728032e823ce964c04cc09a577817a04
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017-2018 Domizio Demichelis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # Pagy
2
+
3
+ Dead simple pagination in pure ruby. Easy, fast and very light. No restrictions imposed: use it with any MVC framework, any ORM, any DB type, any templating system or none at all. Use the built-in templates or create yours the way you want.
4
+
5
+ ## Alpha Version!
6
+
7
+ This gem is still missing documentation. TBD... soon ;).
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'pagy'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install pagy
24
+
25
+ ## Contributing
26
+
27
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ddnexus/pagy.
28
+
29
+ ## License
30
+
31
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,25 @@
1
+ # Pagy uses an internal I18n-like :pagy_t helper that lookup
2
+ # into this file at Pagy.root.join('locale', 'pagy.yml')
3
+ # If you want to customize it you should set:
4
+ # Pagy::Opts.i18n_file = 'path/to/your/file.yaml'
5
+
6
+ # If you need to use this method with pluralization different than english
7
+ # (i.e. not 'zero', 'one', 'other' plurals) then you should define the
8
+ # Pagy::Opts.i18n_plurals proc to return the plural key based on the passed count.
9
+
10
+ en:
11
+ pagy:
12
+ nav:
13
+ prev: "‹ Prev"
14
+ next: "Next ›"
15
+ gap: "…"
16
+ info:
17
+ single_page:
18
+ zero: "No %{item_name} found"
19
+ one: "Displaying <b>1</b> %{item_name}"
20
+ other: "Displaying <b>all %{count}</b> %{item_name}"
21
+ multiple_pages: "Displaying %{item_name} <b>%{from}-%{to}</b> of <b>%{count}</b>"
22
+ item:
23
+ zero: "items"
24
+ one: "item"
25
+ other: "items"
@@ -0,0 +1,42 @@
1
+ class Pagy
2
+ # Including this module (usually in your controller) is handy but totally optional.
3
+ # It basically just encapsulates a couple of verbose statement in one single slick
4
+ # #pagy method, but it does not add any functionality on its own.
5
+ #
6
+ # Using the module allows you to have a predefined method and a few sub-methods
7
+ # (i.e. methods called only by the predefine method) handy if you need to override
8
+ # some aspect of the predefined #pagy method.
9
+ #
10
+ # However, you can just explicitly write your own pagy method in just a couple of
11
+ # lines of code, specially if you need to override two or more methods. For example:
12
+ #
13
+ # def pagy(scope, opts={})
14
+ # pagy = Pagy.new scope.count, page: params[:page], **opts
15
+ # return pagy, scope.offset(pagy.offset).limit(pagy.limit)
16
+ # end
17
+
18
+ module Backend ; private # the whole module is private so no problem including it in a controller
19
+
20
+ def pagy(obj, opts={})
21
+ pagy = Pagy.new(count: pagy_get_count(obj), page: pagy_get_page, i18n_key: pagy_get_i18n_key(obj), **opts)
22
+ return pagy, pagy_get_items(obj, pagy)
23
+ end
24
+
25
+ def pagy_get_count(obj)
26
+ obj.count
27
+ end
28
+
29
+ def pagy_get_page
30
+ params[:page]
31
+ end
32
+
33
+ def pagy_get_i18n_key(obj) end
34
+
35
+ # this should work with ActiveRecord, Sequel, Mongoid...
36
+ # override it if obj does not implement it that way
37
+ def pagy_get_items(obj, pagy)
38
+ obj.offset(pagy.offset).limit(pagy.limit)
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,155 @@
1
+ require 'yaml'
2
+ class Pagy
3
+ # This module supplies a few methods to deal with the navigation aspect of the pagination.
4
+ # You will usually include it in some helper module, eventually overriding the #pagy_url_for
5
+ # in order to fit its behavior with your app needs (e.g.: removing and adding some param or
6
+ # allowing fancy routes, etc.)
7
+ #
8
+ # All the code has been optimized for speed and low memory usage.
9
+ # In particular there are a couple of very specialized methods (pagy_t and pagy_linker_proc)
10
+ # that can be used in place of the equivalent (but general-purpose) framework helpers,
11
+ # in order to dramatically boost speed and reduce memory usage.
12
+ #
13
+ # For example if you use the rails link_to in order to link each page in the pagination bar,
14
+ # you will call 10 or 20 times the same method that has to do a lot of things again and again
15
+ # just to get you (almost) the same string repeated with just the page number replaced.
16
+ # Since pagination is a very specialized process, it is possible to do the same by using
17
+ # a one-line proc that uses just one single string interpolation. Compared to the general-purpose
18
+ # link_to method, the pagy_linker_proc is tens of times faster and uses a very small fraction of the memory.
19
+ #
20
+ # Notice: The code in this module may not look very pretty (as most code dealing with many long strings),
21
+ # but its performance makes it very sexy! ;)
22
+
23
+ module Frontend
24
+
25
+ # Notice: Each long tag-string of the nav methods is written on one single line with a long
26
+ # interpolation in the middle for performance and... (hard to believe) readability reasons.
27
+ #
28
+ # Performance:
29
+ # using the '%' method like in the following example:
30
+ #
31
+ # case item
32
+ # when Integer; '<span class="page">%s</span>' % linker.call(item)
33
+ # when String ; '<span class="page active">%s</span>' % item
34
+ # when :gap ; '<span class="page gap">%s</span>' % pagy_t('pagy.nav.gap')
35
+ # end
36
+ #
37
+ # would look a lot better but the benchmark really sucks! :/
38
+ #
39
+ # Readability:
40
+ # If you disable soft-wrapping in your editor, you can focus on the very simple ruby logic
41
+ # unfolding at the beginning of the lines, without any string-distraction.
42
+ # For the strings: each tag-string has only one interpolation, so at the end they are
43
+ # simple to deal with, even if they look a bit ugly.
44
+
45
+ # Generic pagination: it returns the html with the series of links to the pages
46
+ def pagy_nav(pagy, opts=nil)
47
+ pagy.opts.merge!(opts) if opts ; linker = pagy_linker_proc(pagy) ; tags = [] # init all vars
48
+
49
+ tags << (pagy.prev ? %(<span class="page prev">#{linker.call pagy.prev, pagy_t('pagy.nav.prev'.freeze), 'aria-label="previous"'.freeze}</span>)
50
+ : %(<span class="page prev disabled">#{pagy_t('pagy.nav.prev'.freeze)}</span>))
51
+ pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
52
+ tags << case item
53
+ when Integer; %(<span class="page">#{linker.call item}</span>) # page link
54
+ when String ; %(<span class="page active">#{item}</span>) # current page
55
+ when :gap ; %(<span class="page gap">#{pagy_t('pagy.nav.gap'.freeze)}</span>) # page gap
56
+ end
57
+ end
58
+ tags << (pagy.next ? %(<span class="page next">#{linker.call pagy.next, pagy_t('pagy.nav.next'.freeze), 'aria-label="next"'.freeze}</span>)
59
+ : %(<span class="page next disabled">#{pagy_t('pagy.nav.next'.freeze)}</span>))
60
+ %(<nav class="#{pagy.opts[:class]||'pagination'.freeze}" role="navigation" aria-label="pager">#{tags.join(pagy.opts[:separator]||' '.freeze)}</nav>)
61
+ end
62
+
63
+
64
+ # Pagination for bootstrap: it returns the html with the series of links to the pages
65
+ def pagy_nav_bootstrap(pagy, opts=nil)
66
+ pagy.opts.merge!(opts) if opts ; linker = pagy_linker_proc(pagy) ; tags = [] # init all vars
67
+
68
+ tags << (pagy.prev ? %(<li class="page-item prev">#{linker.call pagy.prev, pagy_t('pagy.nav.prev'.freeze), 'class="page-link" aria-label="previous"'.freeze}</li>)
69
+ : %(<li class="page-item prev disabled"><a href="#" class="page-link">#{pagy_t('pagy.nav.prev'.freeze)}</a></li>))
70
+ pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
71
+ tags << case item
72
+ when Integer; %(<li class="page-item">#{linker.call item, item, 'class="page-link"'.freeze}</li>) # page link
73
+ when String ; %(<li class="page-item active">#{linker.call item, item, 'class="page-link"'.freeze}</li>) # active page
74
+ when :gap ; %(<li class="page-item gap disabled"><a href="#" class="page-link">#{pagy_t('pagy.nav.gap'.freeze)}</a></li>) # page gap
75
+ end
76
+ end
77
+ tags << (pagy.next ? %(<li class="page-item next">#{linker.call pagy.next, pagy_t('pagy.nav.next'.freeze), 'class="page-link" aria-label="next"'.freeze}</li>)
78
+ : %(<li class="page-item next disabled"><a href="#" class="page-link">#{pagy_t('pagy.nav.next'.freeze)}</a></li>))
79
+ %(<nav class="#{pagy.opts[:class]||'pagination'.freeze}" role="navigation" aria-label="pager"><ul class="pagination">#{tags.join}</ul></nav>)
80
+ end
81
+
82
+
83
+ # return examples: "Displaying items 41-60 of 324" or "Displaying Products 41-60 of 324"
84
+ def pagy_info(pagy, vars=nil)
85
+ name = vars && vars[:item_name] || pagy_t(pagy.opts[:i18n_key] || 'pagy.info.item'.freeze, count: pagy.count)
86
+ name = pagy_t('pagy.info.item'.freeze, count: pagy.count) if name.start_with?('translation missing:'.freeze)
87
+ key = pagy.pages == 1 ? 'single_page'.freeze : 'multiple_pages'.freeze
88
+ pagy_t "pagy.info.#{key}", item_name: name, count: pagy.count, from: pagy.from, to: pagy.to
89
+ end
90
+
91
+
92
+ # this works with all Rack-based frameworks (Sinatra, Padrino, Rails, ...)
93
+ def pagy_url_for(n)
94
+ url = File.join(request.script_name.to_s, request.path_info)
95
+ params = request.GET.merge('page' => n.to_s)
96
+ url << '?' << Rack::Utils.build_nested_query(params)
97
+ end
98
+
99
+ # The :pagy_t method is the internal implementation of I18n.t, used when I18n is missing or
100
+ # not needed (for example when your application is a single-locale app, e.g. only 'en', or only 'fr'...).
101
+ #
102
+ # It implements only the very basic functionality of the I18n.t method
103
+ # but it is a lot faster, it uses less memory and it's still good enough for the limited Pagy's needs.
104
+ #
105
+ # You can still use this method with a pluralization different than English
106
+ # (i.e. not 'zero', 'one', 'other' plurals). In that case you should define the
107
+ # Pagy::Opts.i18n_plurals proc to return the plural key based on the passed count.
108
+ #
109
+ # If you need full I18n functionality, you should override this method with something like:
110
+ # def pagy_t(*a); I18n.t(*a) end
111
+ # and add your translations to the I18n usual locales files
112
+
113
+ hash = YAML.load_file Opts.i18n_file || Pagy.root.join('locales', 'pagy.yml')
114
+ DATA = hash[hash.keys.first].freeze
115
+
116
+ # Similar to I18n.t for interpolation and pluralization, with the following constraints:
117
+ # - the path/keys option is supported only in dot-separated string or symbol format
118
+ # - the :scope and :default options are not supported
119
+ # - no exception are raised: the errors are returned as translated strings
120
+ def pagy_t(path, vars={})
121
+ value = DATA.dig(*path.to_s.split('.'.freeze))
122
+ if value.is_a?(Hash)
123
+ vars.has_key?(:count) or return value
124
+ plural = (Opts.i18n_plurals ||= -> (c) {c==0 && 'zero' || c==1 && 'one' || 'other'}).call(vars[:count])
125
+ value.has_key?(plural) or return %(invalid pluralization data: "#{path}" cannot be used with count: #{vars[:count]}; key "#{plural}" is missing.)
126
+ value = value[plural]
127
+ end
128
+ value or return %(translation missing: "#{path}")
129
+ sprintf value, Hash.new{|h,k| "%{#{k}}"}.merge!(vars) # interpolation
130
+ end
131
+
132
+ # This method returns a very efficient proc to produce the page links.
133
+ # The proc is somewhat similar to link_to, but it works a lot faster
134
+ # with a simple one-string-only interpolation.
135
+ # The proc also adds the eventual :link_extra string option to the link tag
136
+ #
137
+ # Notice: all the rendering methods in this module use only strings for fast performance,
138
+ # so use the :link_extra option to add string-formatted attributes like for example:
139
+ # :link_extra => 'data-remote="true" class="special"'
140
+ #
141
+ # This method calls the (possibly overridden and slow) pagy_url_for only once to get the url
142
+ # with the MARKER in place of the page number, then it splits the beginning tag-string at the MARKER
143
+ # and defines a proc that interpolates the two fragments around the real page number with the rest of the tag.
144
+ # Tricky but very fast!
145
+
146
+ MARKER = "-pagy-#{'pagy'.hash}-".freeze
147
+
148
+ def pagy_linker_proc(pagy)
149
+ rel = { pagy.prev=>' rel="prev"'.freeze, pagy.next=>' rel="next"'.freeze }
150
+ a, b = %(<a href="#{pagy_url_for(MARKER)}" #{pagy.opts[:link_extra]}).split(MARKER)
151
+ -> (n, name=n.to_s, extra=''.freeze) { "#{a}#{n}#{b}#{rel[n]||''.freeze} #{extra}>#{name}</a>"}
152
+ end
153
+
154
+ end
155
+ end
data/lib/pagy.rb ADDED
@@ -0,0 +1,61 @@
1
+ require 'pathname'
2
+ require 'ostruct'
3
+
4
+ # This class takes a few integers (such as collection-count, page-number,
5
+ # items-per-page-limit, etc.), does some simple aritmetic and creates a very
6
+ # small object (~3k) with all is needed for pagination and navigation.
7
+ # Notice that it doesn't actually do any pagination, nor navigation... that is
8
+ # done with a few helpers in the Pagy::Backend and Pagy::Frontend modules.
9
+
10
+ class Pagy ; VERSION = '0.3.0'
11
+
12
+ autoload :Backend, 'pagy/backend'
13
+ autoload :Frontend, 'pagy/frontend'
14
+
15
+ class OutOfRangeError < StandardError; end
16
+
17
+ # root pathname to get the path of pagy files like templates or locales
18
+ def self.root; Pathname.new(__FILE__).dirname end
19
+
20
+ # default options
21
+ # limit: max items per page: it gets adjusted for the last page,
22
+ # so it will pull the right items if the collection was pre-limit(ed)
23
+ # offset: the initial offset of the whole collection before pagination
24
+ # set it only if the collection was pre-offset(ted): it gets added to the final offset
25
+ # initial/final: max pages to show from the first/last page
26
+ # before/after: max pages before/after the current page
27
+ Opts = OpenStruct.new(limit:20, offset:0, initial:1, before:4, after:4, final:1)
28
+
29
+ attr_reader :count, :page, :limit, :opts, :pages, :last, :offset, :from, :to, :prev, :next, :series
30
+
31
+ # merge and validate the options, do some simple aritmetic and set the instance variables
32
+ def initialize(opts)
33
+ @opts = Opts.to_h.merge!(opts) # global opts + instance opts (bang faster)
34
+ @opts[:page] = (@opts[:page]||1).to_i # set page to 1 if nil
35
+ [:count, :limit, :offset, :initial, :before, :page, :after, :final].each do |k|
36
+ @opts[k] >= 0 rescue nil || raise(ArgumentError, "expected #{k} >= 0; got #{@opts[k].inspect}")
37
+ instance_variable_set(:"@#{k}", @opts.delete(k)) # set all the metrics variables
38
+ end
39
+ @pages = @last = [(@count.to_f / @limit).ceil, 1].max # cardinal and ordinal meanings
40
+ (1..@last).cover?(@page) || raise(OutOfRangeError, "expected :page in 1..#{last}; got #{@page.inspect}")
41
+ @offset += @limit * (@page - 1) # initial offset + offset for pagination
42
+ @limit = @count % @limit if @page == @last # adjust limit for last page (for pre-limit(ed) collection)
43
+ @from = @count.zero? ? 0 : @offset+1 # page begins from item
44
+ @to = @offset + @limit # page ends to item
45
+ @prev = (@page-1 unless @page == 1) # nil if no prev page
46
+ @next = (@page+1 unless @page == @last) # nil if no next page
47
+ @series = [] # e.g. [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
48
+ all = (0..@last+1) # page range with boundaries
49
+ arund = ([@page-@before, 1].max .. [@page+@after, @last].min).to_a # before..after pages
50
+ row = (all.first(@initial+1) | arund | all.last(@final+1)).sort # pages with boundaries
51
+ row.each_cons(2) do |a, b| # loop in consecutive pairs
52
+ if a+1 == b; @series.push(a) # no gap -> no additions
53
+ elsif a+2 == b; @series.push(a, a+1) # 1 page gap -> fill with next page
54
+ else @series.push(a, :gap) # larger gap -> add :gap
55
+ end # skip the right boundary (last+1)
56
+ end
57
+ @series.shift # remove the left boundary (0)
58
+ @series[@series.index(@page)] = @page.to_s # convert the current page to String
59
+ end
60
+
61
+ end
@@ -0,0 +1,28 @@
1
+ -# This template uses only the pagy_url_for helper, no dependency on any framework
2
+ -# No special optimization for speed and memory. Use the pagy helpers if speed and memory are important.
3
+
4
+ - rel = { pagy.prev => 'prev', pagy.next => 'next' }
5
+
6
+ %nav.pagination{"aria-label" => "pager", :role => "navigation"}
7
+
8
+ %ul.pagination
9
+
10
+ %li.page-item.prev{:class => ('disabled' unless pagy.prev)}
11
+ %a.page-link{:href => (pagy.prev ? pagy_url_for(pagy.prev) : '#'), :rel => "prev", "aria-label"=>"previous"}!= pagy_t('pagy.nav.prev')
12
+
13
+ - pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
14
+ - case item
15
+ - when Integer # page link
16
+ %li.page-item
17
+ %a.page-link{:href => pagy_url_for(item), :rel => rel[item]}= item
18
+
19
+ - when String # current page
20
+ %li.page-item.active
21
+ %a.page-link{:href => pagy_url_for(item)}= item
22
+
23
+ - when :gap # page gap
24
+ %li.page-item.disabled.gap
25
+ %a.page-link{:href => "#"}!= pagy_t('pagy.nav.gap')
26
+
27
+ %li.page-item.next{:class => ('disabled' unless pagy.next)}
28
+ %a.page-link{:href => (pagy.next ? pagy_url_for(pagy.next) : '#'), :rel => "next", "aria-label"=>"next"}!= pagy_t('pagy.nav.next')
@@ -0,0 +1,37 @@
1
+ / This template uses only the pagy_url_for helper, no dependency on any framework
2
+ / No special optimization for speed and memory. Use the pagy helpers if speed and memory are important.
3
+
4
+ - rel = { pagy.prev => 'prev', pagy.next => 'next' }
5
+
6
+ nav.pagination role="navigation" aria-label="pager"
7
+
8
+ ul.pagination
9
+
10
+ - if pagy.prev
11
+ li.page-item.prev
12
+ a.page-link href=pagy_url_for(pagy.prev) rel="prev" aria-label="previous" == pagy_t('pagy.nav.prev')
13
+ - else
14
+ li.page-item.prev.disabled
15
+ a.page-link href="#" == pagy_t('pagy.nav.prev')
16
+
17
+ - pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
18
+ - case item
19
+
20
+ - when Integer # page link
21
+ li.page-item
22
+ a.page-link href=(pagy_url_for(item)) rel=(rel[item]) == item
23
+
24
+ - when String # current page
25
+ li.page-item.active
26
+ a.page-link href=(pagy_url_for(item)) == item
27
+
28
+ - when :gap # page gap
29
+ li.page-item.disabled.gap
30
+ a.page-link href="#" == pagy_t('pagy.nav.gap')
31
+
32
+ - if pagy.next
33
+ li.page-item.next
34
+ a.page-link href=pagy_url_for(pagy.next) rel="next" aria-label="next" == pagy_t('pagy.nav.next')
35
+ - else
36
+ li.page-item.next.disabled
37
+ a.page-link href="#" == pagy_t('pagy.nav.next')
@@ -0,0 +1,46 @@
1
+ <%#
2
+ This template uses only the pagy_url_for helper from pagy and link_to from rails
3
+ No special optimization for speed and memory. Use the pagy helpers if speed and memory are important.
4
+ -%>
5
+ <% rel = { pagy.prev => 'prev', pagy.next => 'next' } %>
6
+
7
+ <nav aria-label="pager" class="pagination" role="navigation">
8
+ <ul class="pagination">
9
+
10
+ <% if pagy.prev -%>
11
+ <li class="page-item prev">
12
+ <%= link_to pagy_t('pagy.nav.prev').html_safe, pagy_url_for(pagy.prev), rel: 'prev', class: 'page-link', 'aria-label': "previous" %>
13
+ </li>
14
+ <% else -%>
15
+ <li class="page-item prev disabled">
16
+ <%= link_to pagy_t('pagy.nav.prev').html_safe, pagy_url_for('#'), class: 'page-link'%>
17
+ </li>
18
+ <% end -%>
19
+
20
+
21
+ <% pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36] -%>
22
+ <% case item
23
+ when Integer -%>
24
+ <li class="page-item"><%== link_to item, pagy_url_for(item), rel: rel[item], class: 'page-link' %></li>
25
+
26
+ <% when String -%>
27
+ <li class="page-item active"><%== link_to item, pagy_url_for(item), class: 'page-link'%></li>
28
+
29
+ <% when :gap -%>
30
+ <li class="page-item disabled gap"><%== link_to pagy_t('pagy.nav.gap').html_safe, '#', class: 'page-link'%></li>
31
+
32
+ <% end -%>
33
+ <% end -%>
34
+
35
+ <% if pagy.next -%>
36
+ <li class="page-item next">
37
+ <%= link_to pagy_t('pagy.nav.next').html_safe, pagy_url_for(pagy.next), rel: 'next', class: 'page-link', 'aria-label': "next" %>
38
+ </li>
39
+ <% else -%>
40
+ <li class="page-item next disabled">
41
+ <%= link_to pagy_t('pagy.nav.next').html_safe, pagy_url_for('#'), class: 'page-link'%>
42
+ </li>
43
+ <% end -%>
44
+
45
+ </ul>
46
+ </nav>
@@ -0,0 +1,31 @@
1
+ -# This template uses only the pagy_url_for helper, no dependency on any framework
2
+ -# No special optimization for speed and memory. Use the pagy helpers if speed and memory are important.
3
+
4
+ - rel = { pagy.prev => 'prev', pagy.next => 'next' }
5
+
6
+ %nav.pagination{"aria-label" => "pager", :role => "navigation"}
7
+
8
+ %span{:class => "page prev #{'disabled' unless pagy.prev}"}
9
+ - if pagy.prev
10
+ %a{:href => pagy_url_for(pagy.prev), :rel => "prev", "aria-label"=>"previous"}!= pagy_t('pagy.nav.prev')
11
+ - else
12
+ != pagy_t('pagy.nav.prev')
13
+
14
+ - pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
15
+ - case item
16
+
17
+ - when Integer # page link
18
+ %span.page
19
+ %a{:href => pagy_url_for(item), :rel => rel[item]}= item
20
+
21
+ - when String # current page
22
+ %span.page.current= item
23
+
24
+ - when :gap # page gap
25
+ %span.page.gap!= pagy_t('pagy.nav.gap')
26
+
27
+ %span{:class => "page next #{'disabled' unless pagy.next}"}
28
+ - if pagy.next
29
+ %a{:href => pagy_url_for(pagy.next), :rel => "next", "aria-label"=>"next"}!= pagy_t('pagy.nav.next')
30
+ - else
31
+ != pagy_t('pagy.nav.next')
@@ -0,0 +1,30 @@
1
+ / This template uses only the pagy_url_for helper, no dependency on any framework
2
+ / No special optimization for speed and memory. Use the pagy helpers if speed and memory are important.
3
+
4
+ - rel = { pagy.prev => 'prev', pagy.next => 'next' }
5
+
6
+ nav.pagination role="navigation" aria-label="pager"
7
+
8
+ span.page.prev> class=('disabled' unless pagy.prev)
9
+ - if pagy.prev
10
+ a href=(pagy_url_for(pagy.prev)) rel="prev" aria-label="previous" == pagy_t('pagy.nav.prev')
11
+ - else
12
+ == pagy_t('pagy.nav.prev')
13
+
14
+ - pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
15
+ - case item
16
+ - when Integer # page link
17
+ span.page>
18
+ a href=(pagy_url_for(item)) rel=(rel[item]) == item
19
+
20
+ - when String # current page
21
+ span.page.current ==> item
22
+
23
+ - when :gap # page gap
24
+ span.page.gap ==> pagy_t('pagy.nav.gap')
25
+
26
+ span.page.next class=('disabled' unless pagy.next)
27
+ - if pagy.next
28
+ a href=(pagy_url_for(pagy.next)) rel="next" aria-label="next" == pagy_t('pagy.nav.next')
29
+ - else
30
+ == pagy_t('pagy.nav.next')
@@ -0,0 +1,32 @@
1
+ <%#
2
+ This template uses only the pagy_url_for helper from pagy and link_to/link_to_if from rails
3
+ No special optimization for speed and memory. Use the pagy helpers if speed and memory are important.
4
+ -%>
5
+ <% rel = { pagy.prev => 'prev', pagy.next => 'next' } %>
6
+
7
+ <nav aria-label="pager" class="pagination" role="navigation">
8
+
9
+ <span class="page prev <%= 'disabled' unless pagy.prev %>">
10
+ <%= link_to_if pagy.prev, pagy_t('pagy.nav.prev').html_safe, pagy_url_for(pagy.prev), rel: 'prev', 'aria-label': "previous" %>
11
+ </span>
12
+
13
+ <% pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36] -%>
14
+ <% case item
15
+
16
+ when Integer -%>
17
+ <span class="page"><%= link_to item, pagy_url_for(item), rel: rel[item] %></span>
18
+
19
+ <% when String -%>
20
+ <span class="page current"><%= item %></span>
21
+
22
+ <% when :gap -%>
23
+ <span class="page gap"><%== pagy_t('pagy.nav.gap') %></span>
24
+
25
+ <% end -%>
26
+ <% end -%>
27
+
28
+ <span class="page next <%= 'disabled' unless pagy.next %>">
29
+ <%= link_to_if pagy.next, pagy_t('pagy.nav.next').html_safe, pagy_url_for(pagy.next), rel: 'next', 'aria-label': "next" %>
30
+ </span>
31
+
32
+ </nav>
@@ -0,0 +1,24 @@
1
+ -# This template uses only the pagy_url_for helper from pagy and link_to/link_to_if from rails
2
+ -# No special optimization for speed and memory. Use the pagy helpers if speed and memory are important.
3
+
4
+ - rel = { pagy.prev => 'prev', pagy.next => 'next' }
5
+
6
+ %nav.pagination{"aria-label" => "pager", :role => "navigation"}
7
+
8
+ %span{:class => "page prev #{'disabled' unless pagy.prev}"}
9
+ = link_to_if pagy.prev, pagy_t('pagy.nav.prev').html_safe, pagy_url_for(pagy.prev), rel: 'prev', 'aria-label': "previous"
10
+
11
+ - pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
12
+ - case item
13
+
14
+ - when Integer # page link
15
+ %span.page= link_to item, pagy_url_for(item), rel: rel[item]
16
+
17
+ - when String # current page
18
+ %span.page.current= item
19
+
20
+ - when :gap # page gap
21
+ %span.page.gap!= pagy_t('pagy.nav.gap')
22
+
23
+ %span{:class => "page next #{'disabled' unless pagy.next}"}
24
+ = link_to_if pagy.next, pagy_t('pagy.nav.next').html_safe, pagy_url_for(pagy.next), rel: 'next', 'aria-label': "next"
@@ -0,0 +1,23 @@
1
+ / This template uses only the pagy_url_for helper from pagy and link_to/link_to_if from rails
2
+ / No special optimization for speed and memory. Use the pagy helpers if speed and memory are important.
3
+
4
+ - rel = { pagy.prev => 'prev', pagy.next => 'next' }
5
+
6
+ nav.pagination role="navigation" aria-label="pager"
7
+
8
+ span.page.prev> class=('disabled' unless pagy.prev)
9
+ == link_to_if pagy.prev, pagy_t('pagy.nav.prev').html_safe, pagy_url_for(pagy.prev), rel: 'prev', 'aria-label': "previous"
10
+
11
+ - pagy.series.each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
12
+ - case item
13
+ - when Integer # page link
14
+ span.page ==> link_to item, pagy_url_for(item), rel: rel[item]
15
+
16
+ - when String # current page
17
+ span.page.current ==> item
18
+
19
+ - when :gap # page gap
20
+ span.page.gap ==> pagy_t('pagy.nav.gap')
21
+
22
+ span.page.next class=('disabled' unless pagy.next)
23
+ == link_to_if pagy.next, pagy_t('pagy.nav.next').html_safe, pagy_url_for(pagy.next), rel: 'next', 'aria-label': "next"
data/pagy.gemspec ADDED
@@ -0,0 +1,32 @@
1
+
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pagy'
5
+ require 'date'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'pagy'
9
+ s.version = Pagy::VERSION
10
+ s.authors = ['Domizio Demichelis']
11
+ s.email = ['dd.nexus@gmail.com']
12
+ s.date = Date.today.to_s
13
+
14
+ s.summary = %q{Because pagination should not suck!}
15
+ s.description = %q{Dead simple pagination in pure ruby. Easy, fast and very light. No restrictions imposed: use it with any MVC framework, any ORM, any DB type, any templating system or none at all. Use the built-in templates or create yours the way you want.}
16
+ s.homepage = 'https://github.com/ddnexus/pagy'
17
+ s.license = 'MIT'
18
+ s.require_paths = ['lib']
19
+
20
+ s.files = `git ls-files -z`.split("\x0")
21
+ .reject{|f| f.start_with? '.', 'test', 'Gemfile', 'Rakefile' }
22
+
23
+ s.add_development_dependency 'bundler', '~> 1.16'
24
+ s.add_development_dependency 'rake', '~> 10.0'
25
+ s.add_development_dependency 'minitest', '~> 5.0'
26
+ s.add_development_dependency 'slim'
27
+ s.add_development_dependency 'haml'
28
+ s.add_development_dependency 'benchmark-ips'
29
+ s.add_development_dependency 'kalibera'
30
+ s.add_development_dependency 'memory_profiler'
31
+
32
+ end
metadata ADDED
@@ -0,0 +1,173 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pagy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Domizio Demichelis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-02-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: slim
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: haml
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: benchmark-ips
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: kalibera
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: memory_profiler
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: 'Dead simple pagination in pure ruby. Easy, fast and very light. No restrictions
126
+ imposed: use it with any MVC framework, any ORM, any DB type, any templating system
127
+ or none at all. Use the built-in templates or create yours the way you want.'
128
+ email:
129
+ - dd.nexus@gmail.com
130
+ executables: []
131
+ extensions: []
132
+ extra_rdoc_files: []
133
+ files:
134
+ - LICENSE.txt
135
+ - README.md
136
+ - lib/locales/pagy.yml
137
+ - lib/pagy.rb
138
+ - lib/pagy/backend.rb
139
+ - lib/pagy/frontend.rb
140
+ - lib/templates/bootstrap-no-dep.html.haml
141
+ - lib/templates/bootstrap-no-dep.html.slim
142
+ - lib/templates/bootstrap-rails-dep.html.erb
143
+ - lib/templates/default-no-dep.html.haml
144
+ - lib/templates/default-no-dep.html.slim
145
+ - lib/templates/default-rails-dep.html.erb
146
+ - lib/templates/default-rails-dep.html.haml
147
+ - lib/templates/default-rails-dep.html.slim
148
+ - pagy.gemspec
149
+ homepage: https://github.com/ddnexus/pagy
150
+ licenses:
151
+ - MIT
152
+ metadata: {}
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: '0'
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubyforge_project:
169
+ rubygems_version: 2.7.4
170
+ signing_key:
171
+ specification_version: 4
172
+ summary: Because pagination should not suck!
173
+ test_files: []