pagy 0.3.0

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.
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: []