From daad628ef1eef06f65a1760d3661cac4a526329c Mon Sep 17 00:00:00 2001 From: Domizio Demichelis Date: Sat, 6 Apr 2024 16:39:33 +0700 Subject: [PATCH 01/11] Improve release automation --- .github/latest_release_body.md | 2 +- scripts/version-bump.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/latest_release_body.md b/.github/latest_release_body.md index a7de6819e..b1689d802 100644 --- a/.github/latest_release_body.md +++ b/.github/latest_release_body.md @@ -11,7 +11,7 @@ If you wish to keep your favorites alive, please, [vote here](https://github.com your side (try the [pagy demo](https://ddnexus.github.io/pagy/playground.md#3-demo-app)) - See the [CHANGELOG](https://ddnexus.github.io/pagy/changelog) for possible breaking changes -### Changes +### Changes in 8.0.2 - Minor change in rails app and RM run config diff --git a/scripts/version-bump.sh b/scripts/version-bump.sh index 92d231588..5de3a4109 100755 --- a/scripts/version-bump.sh +++ b/scripts/version-bump.sh @@ -29,6 +29,7 @@ function bump(){ bump "$ROOT/retype.yml" bump "$ROOT/.github/ISSUE_TEMPLATE/Code.yml" +bump "$ROOT/.github/latest_release_body.md" bump "$ROOT/gem/apps/calendar.ru" bump "$ROOT/gem/apps/demo.ru" bump "$ROOT/gem/apps/rails.ru" From a9cd810d799497f98d6984c0c9e984a88a8f19cd Mon Sep 17 00:00:00 2001 From: Domizio Demichelis Date: Sat, 6 Apr 2024 18:59:09 +0700 Subject: [PATCH 02/11] Removed redundant @pages, aliased with @last --- CHANGELOG.md | 3 ++- docs/api/pagy.md | 7 +++---- gem/lib/pagy.rb | 18 ++++++++++-------- gem/lib/pagy/calendar.rb | 4 ++-- gem/lib/pagy/calendar/day.rb | 2 +- gem/lib/pagy/calendar/month.rb | 2 +- gem/lib/pagy/calendar/quarter.rb | 2 +- gem/lib/pagy/calendar/week.rb | 2 +- gem/lib/pagy/calendar/year.rb | 2 +- gem/lib/pagy/countless.rb | 12 ++++++------ gem/lib/pagy/extras/gearbox.rb | 26 +++++++++++++------------- test/pagy/extras/gearbox_test.rb | 2 +- 12 files changed, 42 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec023372d..29b7ef3c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,8 @@ If you upgrade from version `< 8.0.0` see the following: ## Deprecations -None +- Protected method `Pagy#setup_pages_var`. Use `Pagy#setup_last_var` instead +
## Version 8.0.2 diff --git a/docs/api/pagy.md b/docs/api/pagy.md index 5cea8a693..1a891973c 100644 --- a/docs/api/pagy.md +++ b/docs/api/pagy.md @@ -166,9 +166,9 @@ or `nil`), except the `vars` hash: | `count` | The collection `:count` | | `page` | The current page number | | `items` | The requested number of items for the page | -| `pages` | The number of total pages in the collection (same as `last` but with cardinal meaning) | | `in` | The number of the items in the page | -| `last` | The number of the last page in the collection (same as `pages` but with ordinal meaning) | +| `last` | The number of the last page in the collection (ordinal meaning) | +| `pages` | Alias for `last` (cardinal meaning) | | `offset` | The number of items skipped from the collection in order to get the start of the current page (`:outset` included) | | `from` | The collection-position of the first item in the page (`:outset` excluded) | | `to` | The collection-position of the last item in the page (`:outset` excluded) | @@ -187,7 +187,6 @@ the following peculiar attributes: |:----------|:--------| | `count` | `0` | | `page` | `1` | -| `pages` | `1` | | `last` | `1` | | `in` | `0` | | `from` | `0` | @@ -199,7 +198,7 @@ the following peculiar attributes: Which means: - there is always a `page` #`1` in the pagination, even if it's empty -- `pages` and `last` are always at least both `1` +- `last` is always at least `1` - the `series` array contains always at least the page #`1`, which for a single page is also the current page, thus a string. With `size: []` the `series` method returns `[]` - `in`, `from` and `to` of an empty page are all `0` diff --git a/gem/lib/pagy.rb b/gem/lib/pagy.rb index 9155a94a2..84f2a496a 100644 --- a/gem/lib/pagy.rb +++ b/gem/lib/pagy.rb @@ -28,14 +28,15 @@ def self.root # frontend/helpers anchor_string: nil } - attr_reader :count, :page, :items, :vars, :pages, :last, :offset, :in, :from, :to, :prev, :next, :params, :request_path + attr_reader :count, :page, :items, :vars, :last, :offset, :in, :from, :to, :prev, :next, :params, :request_path + alias pages last # Merge and validate the options, do some simple arithmetic and set the instance variables def initialize(vars) normalize_vars(vars) setup_vars(count: 0, page: 1, outset: 0) setup_items_var - setup_pages_var + setup_last_var setup_offset_var setup_params_var setup_request_path_var @@ -71,12 +72,12 @@ def series(size: @vars[:size], **_) series.push(*start..@last) elsif size.is_a?(Integer) && size.positive? # only central series # The simplest and fastest algorithm - size = @pages if size > @pages # reduce the max size to @pages + size = @last if size > @last # reduce the max size to @last left = ((size - 1) / 2.0).floor # left half might be 1 page shorter for even size start = if @page <= left # beginning pages 1 - elsif @page > @pages - (size - left) # end pages - @pages - size + 1 + elsif @page > @last - (size - left) # end pages + @last - size + 1 else # intermediate pages @page - left end @@ -120,10 +121,11 @@ def setup_items_var setup_vars(items: 1) end - # Setup @pages and @last (overridden by the gearbox extra) - def setup_pages_var - @pages = @last = [(@count.to_f / @items).ceil, 1].max + # Setup @last and @last (overridden by the gearbox extra) + def setup_last_var + @last = [(@count.to_f / @items).ceil, 1].max end + alias setup_pages_var setup_last_var # Setup @offset based on the :gearbox_items variable def setup_offset_var diff --git a/gem/lib/pagy/calendar.rb b/gem/lib/pagy/calendar.rb index af73c71e8..53a618c74 100644 --- a/gem/lib/pagy/calendar.rb +++ b/gem/lib/pagy/calendar.rb @@ -67,7 +67,7 @@ def page_at(time, **opts) Warning.warn "Pagy::Calendar#page_at: Rescued #{time} out of range by returning the #{ordinal} page." end offset = page_offset_at(fit_time) # offset starts from 0 - @order == :asc ? offset + 1 : @pages - offset + @order == :asc ? offset + 1 : @last - offset end # Base class method for the setup of the unit variables (subclasses must implement it and call super) @@ -90,7 +90,7 @@ def localize(time, opts) # Number of time units to offset from the @initial time, in order to get the ordered starting time for the page. # Used in starting_time_for(page) where page starts from 1 (e.g. page to starting_time means subtracting 1) def time_offset_for(page) - @order == :asc ? page - 1 : @pages - page + @order == :asc ? page - 1 : @last - page end # Period of the active page (used internally for nested units) diff --git a/gem/lib/pagy/calendar/day.rb b/gem/lib/pagy/calendar/day.rb index 5815583f9..34575e705 100644 --- a/gem/lib/pagy/calendar/day.rb +++ b/gem/lib/pagy/calendar/day.rb @@ -16,7 +16,7 @@ def setup_unit_vars super @initial = @starting.beginning_of_day @final = @ending.tomorrow.beginning_of_day - @pages = @last = page_offset(@initial, @final) + @last = page_offset(@initial, @final) @from = starting_time_for(@page) @to = @from.tomorrow end diff --git a/gem/lib/pagy/calendar/month.rb b/gem/lib/pagy/calendar/month.rb index 9f256877a..7761b88be 100644 --- a/gem/lib/pagy/calendar/month.rb +++ b/gem/lib/pagy/calendar/month.rb @@ -16,7 +16,7 @@ def setup_unit_vars super @initial = @starting.beginning_of_month @final = @ending.next_month.beginning_of_month - @pages = @last = (months_in(@final) - months_in(@initial)) + @last = (months_in(@final) - months_in(@initial)) @from = starting_time_for(@page) @to = @from.next_month end diff --git a/gem/lib/pagy/calendar/quarter.rb b/gem/lib/pagy/calendar/quarter.rb index 811111abf..135fbcb87 100644 --- a/gem/lib/pagy/calendar/quarter.rb +++ b/gem/lib/pagy/calendar/quarter.rb @@ -23,7 +23,7 @@ def setup_unit_vars super @initial = @starting.beginning_of_quarter @final = @ending.next_quarter.beginning_of_quarter - @pages = @last = (months_in(@final) - months_in(@initial)) / 3 + @last = (months_in(@final) - months_in(@initial)) / 3 @from = starting_time_for(@page) @to = @from.next_quarter end diff --git a/gem/lib/pagy/calendar/week.rb b/gem/lib/pagy/calendar/week.rb index 8fb165a74..00d0eada5 100644 --- a/gem/lib/pagy/calendar/week.rb +++ b/gem/lib/pagy/calendar/week.rb @@ -15,7 +15,7 @@ def setup_unit_vars super @initial = @starting.beginning_of_week @final = @ending.next_week.beginning_of_week - @pages = @last = page_offset(@initial, @final) + @last = page_offset(@initial, @final) @from = starting_time_for(@page) @to = @from.next_week end diff --git a/gem/lib/pagy/calendar/year.rb b/gem/lib/pagy/calendar/year.rb index e48f2b117..42eabbece 100644 --- a/gem/lib/pagy/calendar/year.rb +++ b/gem/lib/pagy/calendar/year.rb @@ -16,7 +16,7 @@ def setup_unit_vars super @initial = @starting.beginning_of_year @final = @ending.next_year.beginning_of_year - @pages = @last = @final.year - @initial.year + @last = @final.year - @initial.year @from = starting_time_for(@page) @to = @from.next_year end diff --git a/gem/lib/pagy/countless.rb b/gem/lib/pagy/countless.rb index ca6e8b247..3fb99f2d3 100644 --- a/gem/lib/pagy/countless.rb +++ b/gem/lib/pagy/countless.rb @@ -19,12 +19,12 @@ def initialize(vars = {}) # rubocop:disable Lint/MissingSuper def finalize(fetched_size) raise OverflowError.new(self, :page, "to be < #{@page}", @page) if fetched_size.zero? && @page > 1 - @pages = @last = (fetched_size > @items ? @page + 1 : @page) - @in = [fetched_size, @items].min - @from = @in.zero? ? 0 : @offset - @outset + 1 - @to = @offset - @outset + @in - @prev = (@page - 1 unless @page == 1) - @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1 + @last = (fetched_size > @items ? @page + 1 : @page) + @in = [fetched_size, @items].min + @from = @in.zero? ? 0 : @offset - @outset + 1 + @to = @offset - @outset + @in + @prev = (@page - 1 unless @page == 1) + @next = @page == @last ? (1 if @vars[:cycle]) : @page + 1 self end diff --git a/gem/lib/pagy/extras/gearbox.rb b/gem/lib/pagy/extras/gearbox.rb index 19822cc90..374f70e4b 100644 --- a/gem/lib/pagy/extras/gearbox.rb +++ b/gem/lib/pagy/extras/gearbox.rb @@ -19,23 +19,23 @@ def setup_items_var @items = gearbox_items[@page - 1] || gearbox_items.last end - # Setup @pages and @last based on the :gearbox_items variable (not used by Pagy::Countless) - def setup_pages_var + # Setup @last based on the :gearbox_items variable (not used by Pagy::Countless) + def setup_last_var return super if !@vars[:gearbox_extra] || @vars[:items_extra] gearbox_items = @vars[:gearbox_items] # This algorithm is thousands of times faster than the one in the geared_pagination gem - @pages = @last = (if @count > (sum = gearbox_items.sum) - [((@count - sum).to_f / gearbox_items.last).ceil, 1].max + gearbox_items.count - else - pages = 0 - remainder = @count - while remainder.positive? - pages += 1 - remainder -= gearbox_items[pages - 1] - end - [pages, 1].max - end) + @last = (if @count > (sum = gearbox_items.sum) + [((@count - sum).to_f / gearbox_items.last).ceil, 1].max + gearbox_items.count + else + pages = 0 + remainder = @count + while remainder.positive? + pages += 1 + remainder -= gearbox_items[pages - 1] + end + [pages, 1].max + end) end # Setup @offset based on the :gearbox_items variable diff --git a/test/pagy/extras/gearbox_test.rb b/test/pagy/extras/gearbox_test.rb index 4d4108de0..b7b271341 100644 --- a/test/pagy/extras/gearbox_test.rb +++ b/test/pagy/extras/gearbox_test.rb @@ -51,7 +51,7 @@ end end - describe '#setup_pages_var' do + describe '#setup_last_var' do it 'can skip gearbox for pages' do _(Pagy.new(count: 90, page: 1, items_extra: true).pages).must_equal 5 _(Pagy.new(count: 103, page: 1, gearbox_extra: false).pages).must_equal 6 From 575ae82131e533f7ccee4ff7b8fe52517e3dd5a2 Mon Sep 17 00:00:00 2001 From: Domizio Demichelis Date: Sat, 6 Apr 2024 19:35:20 +0700 Subject: [PATCH 03/11] Fix old link_extra arg in tests --- gem/config/pagy.rb | 16 +++++------ test/pagy/backend_test.rb | 16 +++++------ test/pagy/extras/arel_test.rb | 16 +++++------ test/pagy/extras/array_test.rb | 10 +++---- test/pagy/extras/elasticsearch_rails_test.rb | 30 ++++++++++---------- test/pagy/extras/meilisearch_test.rb | 18 ++++++------ test/pagy/extras/searchkick_test.rb | 18 ++++++------ 7 files changed, 62 insertions(+), 62 deletions(-) diff --git a/gem/config/pagy.rb b/gem/config/pagy.rb index 0ad70d0dc..79b754385 100644 --- a/gem/config/pagy.rb +++ b/gem/config/pagy.rb @@ -18,14 +18,14 @@ # Other Variables # See https://ddnexus.github.io/pagy/docs/api/pagy#other-variables -# Pagy::DEFAULT[:size] = [1,4,4,1] # default in pagy < 7.0 -# Pagy::DEFAULT[:page_param] = :page # default -# Pagy::DEFAULT[:fragment] = '#fragment' # example -# Pagy::DEFAULT[:link_extra] = 'data-remote="true"' # example -# Pagy::DEFAULT[:cycle] = true # example -# Pagy::DEFAULT[:request_path] = '/foo' # example -# Pagy::DEFAULT[:count_args] = [] # example for non AR ORMs -# Pagy::DEFAULT[:params] = {} # default +# Pagy::DEFAULT[:size] = [1,4,4,1] # default in pagy < 7.0 +# Pagy::DEFAULT[:page_param] = :page # default +# Pagy::DEFAULT[:fragment] = '#fragment' # example +# Pagy::DEFAULT[:anchor_string] = 'data-remote="true"' # example +# Pagy::DEFAULT[:cycle] = true # example +# Pagy::DEFAULT[:request_path] = '/foo' # example +# Pagy::DEFAULT[:count_args] = [] # example for non AR ORMs +# Pagy::DEFAULT[:params] = {} # default # NOTICE: The :params can be also set as a lambda e.g: # ->(params){ params.exclude('useless').merge!('custom' => 'useful') } diff --git a/test/pagy/backend_test.rb b/test/pagy/backend_test.rb index 5536ab1b8..64d50e104 100644 --- a/test/pagy/backend_test.rb +++ b/test/pagy/backend_test.rb @@ -22,12 +22,12 @@ _(records).must_equal [41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60] end it 'paginates with vars' do - pagy, records = app.send(:pagy, @collection, page: 2, items: 10, link_extra: 'X') + pagy, records = app.send(:pagy, @collection, page: 2, items: 10, anchor_string: 'X') _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 10 _(pagy.page).must_equal 2 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' _(records.count).must_equal 10 _(records).must_equal [11, 12, 13, 14, 15, 16, 17, 18, 19, 20] end @@ -46,30 +46,30 @@ _(merged[:page]).must_equal 3 end it 'gets vars' do - vars = { page: 2, items: 10, link_extra: 'X' } + vars = { page: 2, items: 10, anchor_string: 'X' } merged = app.send :pagy_get_vars, @collection, vars _(merged.keys).must_include :count _(merged.keys).must_include :page _(merged.keys).must_include :items - _(merged.keys).must_include :link_extra + _(merged.keys).must_include :anchor_string _(merged[:count]).must_equal 1000 _(merged[:page]).must_equal 2 _(merged[:items]).must_equal 10 - _(merged[:link_extra]).must_equal 'X' + _(merged[:anchor_string]).must_equal 'X' end it 'works with grouped collections' do collection = MockCollection::Grouped.new((1..1000).to_a) - vars = { page: 2, items: 10, link_extra: 'X' } + vars = { page: 2, items: 10, anchor_string: 'X' } merged = app.send :pagy_get_vars, collection, vars _(collection.count.size).must_equal 1000 _(merged.keys).must_include :count _(merged.keys).must_include :page _(merged.keys).must_include :items - _(merged.keys).must_include :link_extra + _(merged.keys).must_include :anchor_string _(merged[:count]).must_equal 1000 _(merged[:page]).must_equal 2 _(merged[:items]).must_equal 10 - _(merged[:link_extra]).must_equal 'X' + _(merged[:anchor_string]).must_equal 'X' end it 'overrides count and page' do vars = { count: 10, page: 32 } diff --git a/test/pagy/extras/arel_test.rb b/test/pagy/extras/arel_test.rb index 7247a0d52..b08be2545 100644 --- a/test/pagy/extras/arel_test.rb +++ b/test/pagy/extras/arel_test.rb @@ -24,12 +24,12 @@ _(items).must_equal [41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60] end it 'paginates with vars' do - pagy, items = app.send(:pagy_arel, @collection, page: 2, items: 10, link_extra: 'X') + pagy, items = app.send(:pagy_arel, @collection, page: 2, items: 10, anchor_string: 'X') _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 10 _(pagy.page).must_equal 2 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' _(items.size).must_equal 10 _(items).must_equal [11, 12, 13, 14, 15, 16, 17, 18, 19, 20] end @@ -48,29 +48,29 @@ _(merged[:page]).must_equal 3 end it 'gets vars' do - vars = { page: 2, items: 10, link_extra: 'X' } + vars = { page: 2, items: 10, anchor_string: 'X' } merged = app.send :pagy_arel_get_vars, @collection, vars _(merged.keys).must_include :count _(merged.keys).must_include :page _(merged.keys).must_include :items - _(merged.keys).must_include :link_extra + _(merged.keys).must_include :anchor_string _(merged[:count]).must_equal 1000 _(merged[:page]).must_equal 2 _(merged[:items]).must_equal 10 - _(merged[:link_extra]).must_equal 'X' + _(merged[:anchor_string]).must_equal 'X' end it 'works with grouped collections' do collection = MockCollection::Grouped.new((1..1000).to_a) - vars = { page: 2, items: 10, link_extra: 'X' } + vars = { page: 2, items: 10, anchor_string: 'X' } merged = app.send :pagy_arel_get_vars, collection, vars _(merged.keys).must_include :count _(merged.keys).must_include :page _(merged.keys).must_include :items - _(merged.keys).must_include :link_extra + _(merged.keys).must_include :anchor_string _(merged[:count]).must_equal 1000 _(merged[:page]).must_equal 2 _(merged[:items]).must_equal 10 - _(merged[:link_extra]).must_equal 'X' + _(merged[:anchor_string]).must_equal 'X' end it 'overrides count and page' do vars = { count: 10, page: 32 } diff --git a/test/pagy/extras/array_test.rb b/test/pagy/extras/array_test.rb index a96c3538c..de8ab5327 100644 --- a/test/pagy/extras/array_test.rb +++ b/test/pagy/extras/array_test.rb @@ -22,12 +22,12 @@ _(items).must_equal [41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60] end it 'paginates with vars' do - pagy, items = app.send(:pagy_array, @collection, page: 2, items: 10, link_extra: 'X') + pagy, items = app.send(:pagy_array, @collection, page: 2, items: 10, anchor_string: 'X') _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 10 _(pagy.page).must_equal 2 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' _(items.count).must_equal 10 _(items).must_equal [11, 12, 13, 14, 15, 16, 17, 18, 19, 20] end @@ -46,16 +46,16 @@ _(merged[:page]).must_equal 3 end it 'gets vars' do - vars = { page: 2, items: 10, link_extra: 'X' } + vars = { page: 2, items: 10, anchor_string: 'X' } merged = app.send :pagy_array_get_vars, @collection, vars _(merged.keys).must_include :count _(merged.keys).must_include :page _(merged.keys).must_include :items - _(merged.keys).must_include :link_extra + _(merged.keys).must_include :anchor_string _(merged[:count]).must_equal 1000 _(merged[:page]).must_equal 2 _(merged[:items]).must_equal 10 - _(merged[:link_extra]).must_equal 'X' + _(merged[:anchor_string]).must_equal 'X' end end end diff --git a/test/pagy/extras/elasticsearch_rails_test.rb b/test/pagy/extras/elasticsearch_rails_test.rb index a53276caa..42a997866 100644 --- a/test/pagy/extras/elasticsearch_rails_test.rb +++ b/test/pagy/extras/elasticsearch_rails_test.rb @@ -53,24 +53,24 @@ it 'paginates with vars' do pagy, records = app.send(:pagy_elasticsearch_rails, MockElasticsearchRails::Model.pagy_search('b').records, - page: 2, items: 10, link_extra: 'X') + page: 2, items: 10, anchor_string: 'X') _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 10 _(pagy.page).must_equal 2 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' _(records.count).must_equal 10 _(records).must_rematch :records end it 'paginates with overflow' do pagy, records = app.send(:pagy_elasticsearch_rails, MockElasticsearchRails::Model.pagy_search('b').records, - page: 200, items: 10, link_extra: 'X', overflow: :last_page) + page: 200, items: 10, anchor_string: 'X', overflow: :last_page) _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 10 _(pagy.page).must_equal 100 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' _(records.count).must_equal 10 _(records).must_rematch :records end @@ -103,24 +103,24 @@ it 'paginates with vars' do pagy, records = app.send(:pagy_elasticsearch_rails, MockElasticsearchRails::ModelES7.pagy_search('b').records, - page: 2, items: 10, link_extra: 'X') + page: 2, items: 10, anchor_string: 'X') _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 10 _(pagy.page).must_equal 2 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' _(records.count).must_equal 10 _(records).must_rematch :records end it 'paginates with overflow' do pagy, records = app.send(:pagy_elasticsearch_rails, MockElasticsearchRails::Model.pagy_search('b').records, - page: 200, items: 10, link_extra: 'X', overflow: :last_page) + page: 200, items: 10, anchor_string: 'X', overflow: :last_page) _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 10 _(pagy.page).must_equal 100 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' _(records.count).must_equal 10 _(records).must_rematch :records end @@ -136,14 +136,14 @@ _(merged[:items]).must_equal 20 end it 'gets vars' do - vars = { page: 2, items: 10, link_extra: 'X' } + vars = { page: 2, items: 10, anchor_string: 'X' } merged = app.send :pagy_elasticsearch_rails_get_vars, nil, vars _(merged.keys).must_include :page _(merged.keys).must_include :items - _(merged.keys).must_include :link_extra + _(merged.keys).must_include :anchor_string _(merged[:page]).must_equal 2 _(merged[:items]).must_equal 10 - _(merged[:link_extra]).must_equal 'X' + _(merged[:anchor_string]).must_equal 'X' end end @@ -158,12 +158,12 @@ end it 'paginates response with vars' do response = MockElasticsearchRails::Model.search('b', from: 15, size: 15) - pagy = Pagy.new_from_elasticsearch_rails(response, link_extra: 'X') + pagy = Pagy.new_from_elasticsearch_rails(response, anchor_string: 'X') _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 15 _(pagy.page).must_equal 2 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' end it 'paginates response with defaults on Elasticsearch 5' do response = MockElasticsearchRails::ModelES5.search('a') @@ -175,12 +175,12 @@ end it 'paginates response with vars on Elasticsearch 5' do response = MockElasticsearchRails::ModelES5.search('b', from: 15, size: 15) - pagy = Pagy.new_from_elasticsearch_rails(response, link_extra: 'X') + pagy = Pagy.new_from_elasticsearch_rails(response, anchor_string: 'X') _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 15 _(pagy.page).must_equal 2 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' end end end diff --git a/test/pagy/extras/meilisearch_test.rb b/test/pagy/extras/meilisearch_test.rb index df307fcae..8bfa57742 100644 --- a/test/pagy/extras/meilisearch_test.rb +++ b/test/pagy/extras/meilisearch_test.rb @@ -38,23 +38,23 @@ end it 'paginates with vars' do pagy, results = app.send(:pagy_meilisearch, MockMeilisearch::Model.pagy_search('b'), - page: 2, items: 10, link_extra: 'X') + page: 2, items: 10, anchor_string: 'X') _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 10 _(pagy.page).must_equal 2 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' _(results.length).must_equal 10 _(results.to_a).must_rematch :results end it 'paginates with overflow' do pagy, results = app.send(:pagy_meilisearch, MockMeilisearch::Model.pagy_search('b'), - page: 200, items: 10, link_extra: 'X', overflow: :last_page) + page: 200, items: 10, anchor_string: 'X', overflow: :last_page) _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 10 _(pagy.page).must_equal 100 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' _(results.length).must_equal 10 _(results.to_a).must_rematch :results end @@ -70,14 +70,14 @@ _(merged[:items]).must_equal 20 end it 'gets vars' do - vars = { page: 2, items: 10, link_extra: 'X' } + vars = { page: 2, items: 10, anchor_string: 'X' } merged = app.send :pagy_meilisearch_get_vars, nil, vars _(merged.keys).must_include :page _(merged.keys).must_include :items - _(merged.keys).must_include :link_extra + _(merged.keys).must_include :anchor_string _(merged[:page]).must_equal 2 _(merged[:items]).must_equal 10 - _(merged[:link_extra]).must_equal 'X' + _(merged[:anchor_string]).must_equal 'X' end end @@ -92,12 +92,12 @@ end it 'paginates results with vars' do results = MockMeilisearch::Model.ms_search('b', hits_per_page: 15, page: 3) - pagy = Pagy.new_from_meilisearch(results, link_extra: 'X') + pagy = Pagy.new_from_meilisearch(results, anchor_string: 'X') _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 15 _(pagy.page).must_equal 3 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' end end end diff --git a/test/pagy/extras/searchkick_test.rb b/test/pagy/extras/searchkick_test.rb index d586f586e..722322f95 100644 --- a/test/pagy/extras/searchkick_test.rb +++ b/test/pagy/extras/searchkick_test.rb @@ -64,23 +64,23 @@ end it 'paginates with vars' do pagy, results = app.send(:pagy_searchkick, MockSearchkick::Model.pagy_search('b').results, - page: 2, items: 10, link_extra: 'X') + page: 2, items: 10, anchor_string: 'X') _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 10 _(pagy.page).must_equal 2 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' _(results.count).must_equal 10 _(results).must_rematch :results end it 'paginates with overflow' do pagy, results = app.send(:pagy_searchkick, MockSearchkick::Model.pagy_search('b').results, - page: 200, items: 10, link_extra: 'X', overflow: :last_page) + page: 200, items: 10, anchor_string: 'X', overflow: :last_page) _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 10 _(pagy.page).must_equal 100 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' _(results.count).must_equal 10 _(results).must_rematch :results end @@ -96,14 +96,14 @@ _(merged[:items]).must_equal 20 end it 'gets vars' do - vars = { page: 2, items: 10, link_extra: 'X' } + vars = { page: 2, items: 10, anchor_string: 'X' } merged = app.send :pagy_searchkick_get_vars, nil, vars _(merged.keys).must_include :page _(merged.keys).must_include :items - _(merged.keys).must_include :link_extra + _(merged.keys).must_include :anchor_string _(merged[:page]).must_equal 2 _(merged[:items]).must_equal 10 - _(merged[:link_extra]).must_equal 'X' + _(merged[:anchor_string]).must_equal 'X' end end @@ -118,12 +118,12 @@ end it 'paginates results with vars' do results = MockSearchkick::Model.search('b', page: 2, per_page: 15) - pagy = Pagy.new_from_searchkick(results, link_extra: 'X') + pagy = Pagy.new_from_searchkick(results, anchor_string: 'X') _(pagy).must_be_instance_of Pagy _(pagy.count).must_equal 1000 _(pagy.items).must_equal 15 _(pagy.page).must_equal 2 - _(pagy.vars[:link_extra]).must_equal 'X' + _(pagy.vars[:anchor_string]).must_equal 'X' end end end From 662ee68b6e0080a205c1a4135d9f37ad48dac4ed Mon Sep 17 00:00:00 2001 From: Domizio Demichelis Date: Sat, 6 Apr 2024 19:56:39 +0700 Subject: [PATCH 04/11] Fix minor string typos --- src/main.js | 2 +- test/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.js b/src/main.js index 98f36c167..1dea3abed 100644 --- a/src/main.js +++ b/src/main.js @@ -1,3 +1,3 @@ import Pagy from "./pagy-module"; -// Toplevel var (needed for generating the production file) +// Toplevel var (needed to generate the production file) window.Pagy = Pagy; diff --git a/test/README.md b/test/README.md index c631280e8..46170faf3 100644 --- a/test/README.md +++ b/test/README.md @@ -4,7 +4,7 @@ Ruby is tested with `minitest` through `rake` tasks. ## Run the Ruby tests -Almost every test recreates a different environment and must run in a separate process in order to avoid to override other tests. That means that you can run a single test file (or a single spec in a test file) and it will be OK, but you cannot run a directory of test file, with a single minitest command because they will interfere with each other and will fail. +Almost every test recreates a different environment and must run in a separate process in order to avoid to override other tests. That means that you can run a single test file (or a single spec in a test file) and it will be OK, but you cannot run a directory of test files, with a single minitest command because they will interfere with each other and will fail. ### Rake tasks From e5aa702d05f1be2f49685fdcf34dd2efbdd40c00 Mon Sep 17 00:00:00 2001 From: Domizio Demichelis Date: Sat, 6 Apr 2024 20:08:41 +0700 Subject: [PATCH 05/11] Comment out the :performance gem group --- Gemfile | 10 +++++----- Gemfile.lock | 10 ---------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/Gemfile b/Gemfile index 1f2b0a6df..12ee174ed 100644 --- a/Gemfile +++ b/Gemfile @@ -34,8 +34,8 @@ group :apps do gem 'sinatra-contrib' end -group :performance do - gem 'benchmark-ips' - gem 'kalibera' - gem 'memory_profiler' -end +# group :performance do +# gem 'benchmark-ips' +# gem 'kalibera' +# gem 'memory_profiler' +# end diff --git a/Gemfile.lock b/Gemfile.lock index 9f6f494e2..c088f753e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -16,7 +16,6 @@ GEM ansi (1.5.0) ast (2.4.2) base64 (0.2.0) - benchmark-ips (2.13.0) bigdecimal (3.1.7) builder (3.2.4) concurrent-ruby (1.2.3) @@ -40,9 +39,6 @@ GEM i18n (1.14.4) concurrent-ruby (~> 1.0) json (2.7.2) - kalibera (0.1.2) - memoist (~> 0.16) - rbzip2 (~> 0.3) language_server-protocol (3.17.0.3) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) @@ -50,8 +46,6 @@ GEM llhttp-ffi (0.5.0) ffi-compiler (~> 1.0) rake (~> 13.0) - memoist (0.16.2) - memory_profiler (1.0.1) minitest (5.22.3) minitest-reporters (1.6.1) ansi @@ -87,7 +81,6 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - rbzip2 (0.3.0) readline-ext (0.2.0) regexp_parser (2.9.0) rematch (2.1.0) @@ -149,11 +142,8 @@ PLATFORMS DEPENDENCIES activesupport - benchmark-ips http i18n - kalibera - memory_profiler minitest minitest-reporters oj From 70c75de7b81a8c1e6f69228744813c14b44ce054 Mon Sep 17 00:00:00 2001 From: Domizio Demichelis Date: Sun, 7 Apr 2024 11:36:52 +0700 Subject: [PATCH 06/11] Remove nil variables from DEFAULT --- docs/api/pagy.md | 6 ++-- gem/lib/pagy.rb | 22 +++++------- test/pagy/extras/metadata_test.rb.rematch | 43 +++++++++++------------ test/pagy_test.rb | 5 +-- 4 files changed, 32 insertions(+), 44 deletions(-) diff --git a/docs/api/pagy.md b/docs/api/pagy.md index 1a891973c..f0c0edafe 100644 --- a/docs/api/pagy.md +++ b/docs/api/pagy.md @@ -147,7 +147,7 @@ They are all integers: | `:size` | The size of the page links to show: can be an array of initial pages, before current page, after current page, final pages or the total page size. _(see also [How to control the page links](/docs/how-to.md#control-the-page-links))_ | `7` | | `:page_param` | The name of the page param name used in the url. _(see [How to customize the page param](/docs/how-to.md#customize-the-page-param))_ | `:page` | | `:params` | It can be a `Hash` of params to add to the URL, or a `Proc` that can edit/add/delete the request params _(see [How to customize the params](/docs/how-to.md#customize-the-params))_ | `{}` | -| `:fragment` | The arbitrary fragment string (including the "#") to add to the url. _(see [How to customize the params](/docs/how-to.md#customize-the-params))_ | `''` | +| `:fragment` | The arbitrary fragment string (including the "#") to add to the url. _(see [How to customize the params](/docs/how-to.md#customize-the-params))_ | `nil` | | `:anchor_string` | The extra attributes string (formatted as a valid HTML attribute/value pairs) added to the page links _(see [How to customize the link attributes](/docs/how-to.md#customize-the-link-attributes))_ | `nil` | | `:cycle` | Enable cycling/circular/infinite pagination: `true` sets `next` to `1` when the current page is the last page | `false` | | `:request_path` | Allows overriding the request path for pagination links. Pass the path only (not the absolute url). _(see [Customize the request path](/docs/how-to.md#customize-the-request-path))_ | `nil` | @@ -167,8 +167,8 @@ or `nil`), except the `vars` hash: | `page` | The current page number | | `items` | The requested number of items for the page | | `in` | The number of the items in the page | -| `last` | The number of the last page in the collection (ordinal meaning) | -| `pages` | Alias for `last` (cardinal meaning) | +| `last` | The number of the last page in the collection (ordinal meaning) | +| `pages` | Alias for `last` (cardinal meaning) | | `offset` | The number of items skipped from the collection in order to get the start of the current page (`:outset` included) | | `from` | The collection-position of the first item in the page (`:outset` excluded) | | `to` | The collection-position of the last item in the page (`:outset` excluded) | diff --git a/gem/lib/pagy.rb b/gem/lib/pagy.rb index 84f2a496a..79f0093f2 100644 --- a/gem/lib/pagy.rb +++ b/gem/lib/pagy.rb @@ -13,20 +13,14 @@ def self.root end # Core defult: constant for easy access, but mutable for customizable defaults - DEFAULT = { page: 1, # rubocop:disable Style/MutableConstant - items: 20, - outset: 0, - size: 7, - cycle: false, - # backend/collection - count_args: [:all], # AR friendly - # backend/url - params: {}, - page_param: :page, - fragment: '', - request_path: nil, - # frontend/helpers - anchor_string: nil } + DEFAULT = { page: 1, # rubocop:disable Style/MutableConstant + items: 20, + outset: 0, + size: 7, + cycle: false, + count_args: [:all], # AR friendly + params: {}, + page_param: :page } attr_reader :count, :page, :items, :vars, :last, :offset, :in, :from, :to, :prev, :next, :params, :request_path alias pages last diff --git a/test/pagy/extras/metadata_test.rb.rematch b/test/pagy/extras/metadata_test.rb.rematch index b43381efb..797a3890d 100644 --- a/test/pagy/extras/metadata_test.rb.rematch +++ b/test/pagy/extras/metadata_test.rb.rematch @@ -15,6 +15,26 @@ pagy/extras/metadata::#pagy_metadata for Pagy::Calendar#test_0002_returns only s :prev: 2 :next: 4 :pages: 26 +pagy/extras/metadata::#pagy_metadata for Pagy#test_0001_defines all metadata: + :metadata: + - :scaffold_url + - :first_url + - :prev_url + - :page_url + - :next_url + - :last_url + - :count + - :page + - :items + - :vars + - :pages + - :last + - :in + - :from + - :to + - :prev + - :next + - :series pagy/extras/metadata::#pagy_metadata for Pagy#test_0002_returns the full pagy metadata: :metadata: :scaffold_url: "/foo?page=__pagy_page__" @@ -40,9 +60,6 @@ pagy/extras/metadata::#pagy_metadata for Pagy#test_0002_returns the full pagy me - :all :params: {} :page_param: :page - :fragment: '' - :request_path: - :anchor_string: :countless_minimal: false :steps: false :metadata: @@ -102,23 +119,3 @@ pagy/extras/metadata::#pagy_metadata for Pagy#test_0004_returns only specific me :prev: 2 :next: 4 :pages: 50 -pagy/extras/metadata::#pagy_metadata for Pagy#test_0001_defines all metadata: - :metadata: - - :scaffold_url - - :first_url - - :prev_url - - :page_url - - :next_url - - :last_url - - :count - - :page - - :items - - :vars - - :pages - - :last - - :in - - :from - - :to - - :prev - - :next - - :series diff --git a/test/pagy_test.rb b/test/pagy_test.rb index e436baeff..42ce5fa3c 100644 --- a/test/pagy_test.rb +++ b/test/pagy_test.rb @@ -304,7 +304,7 @@ def series_for(page, *expected) end it 'initializes the request_path' do pagy = Pagy.new(count: 100, request_path: '/foo') - _(pagy.request_path).must_equal('/foo') + _(pagy.vars[:request_path]).must_equal('/foo') end end @@ -327,9 +327,6 @@ def series_for(page, *expected) _(Pagy::DEFAULT[:size]).must_equal 7 _(Pagy::DEFAULT[:page_param]).must_equal :page _(Pagy::DEFAULT[:params]).must_equal({}) - _(Pagy::DEFAULT[:fragment]).must_equal('') - _(Pagy::DEFAULT[:request_path]).must_be_nil - _(Pagy::DEFAULT[:anchor_string]).must_be_nil end end From 8d0b15239b64016c92f3bdc93025390f78c43ef1 Mon Sep 17 00:00:00 2001 From: Domizio Demichelis Date: Sun, 7 Apr 2024 11:37:26 +0700 Subject: [PATCH 07/11] Improve efficiency of params in pagy_url_for --- gem/lib/pagy/extras/standalone.rb | 4 ++-- gem/lib/pagy/url_helpers.rb | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/gem/lib/pagy/extras/standalone.rb b/gem/lib/pagy/extras/standalone.rb index 25eb1018c..8f9524560 100644 --- a/gem/lib/pagy/extras/standalone.rb +++ b/gem/lib/pagy/extras/standalone.rb @@ -42,9 +42,9 @@ def pagy_url_for(pagy, page, absolute: false, **_) return super unless pagy.vars[:url] vars = pagy.vars - params = pagy.params.is_a?(Hash) ? pagy.params.clone : {} # safe when it gets reused + params = vars[:params].is_a?(Hash) ? vars[:params].clone : {} # safe when it gets reused pagy_set_query_params(page, vars, params) - params = pagy.params.call(params) if pagy.params.is_a?(Proc) + params = vars[:params].(params) if vars[:params].is_a?(Proc) query_string = "?#{QueryUtils.build_nested_query(params)}" "#{vars[:url]}#{query_string}#{vars[:fragment]}" end diff --git a/gem/lib/pagy/url_helpers.rb b/gem/lib/pagy/url_helpers.rb index c7ad4b200..34d64d78b 100644 --- a/gem/lib/pagy/url_helpers.rb +++ b/gem/lib/pagy/url_helpers.rb @@ -8,19 +8,19 @@ module UrlHelpers # For non-rack environments you can use the standalone extra def pagy_url_for(pagy, page, absolute: false, **_) vars = pagy.vars - pagy_params = pagy.params.is_a?(Hash) ? pagy.params.transform_keys(&:to_s) : {} - params = request.GET.merge(pagy_params) - pagy_set_query_params(page, vars, params) - params = pagy.params.call(params) if pagy.params.is_a?(Proc) - query_string = "?#{Rack::Utils.build_nested_query(params)}" + query_params = request.GET + query_params.merge!(vars[:params].transform_keys(&:to_s)) if vars[:params].is_a?(Hash) + pagy_set_query_params(page, vars, query_params) + query_params = vars[:params].(query_params) if vars[:params].is_a?(Proc) + query_string = "?#{Rack::Utils.build_nested_query(query_params)}" "#{request.base_url if absolute}#{vars[:request_path] || request.path}#{query_string}#{vars[:fragment]}" end # Add the page and items params # Overridable by the jsonapi extra - def pagy_set_query_params(page, vars, params) - params[vars[:page_param].to_s] = page - params[vars[:items_param].to_s] = vars[:items] if vars[:items_extra] + def pagy_set_query_params(page, vars, query_params) + query_params[vars[:page_param].to_s] = page + query_params[vars[:items_param].to_s] = vars[:items] if vars[:items_extra] end end end From 1e4829fe6391a6c9dc48f00ba7bd9579bfea259b Mon Sep 17 00:00:00 2001 From: Domizio Demichelis Date: Tue, 9 Apr 2024 08:06:31 +0700 Subject: [PATCH 08/11] Improve code issue template --- .github/ISSUE_TEMPLATE/Code.yml | 35 ++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Code.yml b/.github/ISSUE_TEMPLATE/Code.yml index bd5e7c0ff..d79bd6592 100644 --- a/.github/ISSUE_TEMPLATE/Code.yml +++ b/.github/ISSUE_TEMPLATE/Code.yml @@ -37,17 +37,46 @@ body: OR it will be automatically closed!** - #### Valid code files + #### VALID code files - Edited copy of a single-file APP from the [Pagy Playground](https://ddnexus.github.io/pagy/playground) - Link to a pagy fork containing an added test file - - A plain ruby file that can run as a single command `ruby issue_123.rb` + - A plain ruby file that can run as a single command like `ruby my_issue.rb` _(without any other setup step, installation or guessing, and with no or minimal interaction required)_ + #### INVALID "code" + + + - EVERYTHING other than the above! + + - Totally useless things like (but not limited to): + + - Code snippets + + - Multiple files + + - Complex setup + + - Complete applications + + - Any description of errors generated by running your own code + + - Rationalizations about "WHY" and "WHAT" you think it's a bug + + + Please, understand that we won't guess your environment/usage/configuration/conflicts out of some snippet + or description, nor clone/install/setup/debug your complete application. + + + Please, start from a [pagy APP](https://ddnexus.github.io/pagy/playground/#pagy-apps) + and add the minimum that makes it fail. It's a very simple process and, most of the times, + it will make your issue just "disappear". ;) + + _If anything is unclear to you, please ask for [support](https://github.com/ddnexus/pagy/discussions/categories/q-a). We will be happy to help._ @@ -66,7 +95,7 @@ body: attributes: label: Description placeholder: > - 1. Describe what actually happens + 1. Describe what actually happens WITH THE CODE FILE you provided 2. Describe what should happen instead validations: From 8929ab3aa0eade1cf672fc0577ab7acfd76fb898 Mon Sep 17 00:00:00 2001 From: Domizio Demichelis Date: Tue, 9 Apr 2024 08:07:03 +0700 Subject: [PATCH 09/11] Implement max_pages to limit the pagination regardless the actual count --- docs/api/pagy.md | 78 +++++++++++++++----------------- docs/how-to.md | 47 +++++++++++++++---- gem/lib/pagy.rb | 4 +- gem/lib/pagy/countless.rb | 5 +- gem/lib/pagy/extras/gearbox.rb | 33 +++++++------- test/pagy/extras/gearbox_test.rb | 35 +++++++++----- test/pagy_test.rb | 8 +++- 7 files changed, 130 insertions(+), 80 deletions(-) diff --git a/docs/api/pagy.md b/docs/api/pagy.md index f0c0edafe..be88a980c 100644 --- a/docs/api/pagy.md +++ b/docs/api/pagy.md @@ -113,48 +113,44 @@ for `Pagy::Calendar` instances. It returns the page label that will get displaye ## Variables -All the variables passed to the new method will be merged with the `Pagy::DEFAULT` hash and will be kept in the object, passed +All the variables passed to the new method are merged with the `Pagy::DEFAULT` hash and are kept in the object, passed around with it and accessible through the `pagy.vars` hash. They can be set globally by using the `Pagy::DEFAULT` hash or passed to the `Pagy.new` method and are accessible through the `vars` reader. -**Notice**: Pagy replaces the blank values of the passed variables with their default values coming from the `Pagy::DEFAULT` hash. -It also applies `to_i` on the values expected to be integers, so you can use values from request `params` without problems. For -example: `pagy(some_scope, items: params[:items])` will work without any additional cleanup. - -### Instance Variables +!!!success +Pagy replaces the blank values of the passed variables with their default values coming from the `Pagy::DEFAULT` hash. +It also applies `to_i` on the values expected to be integers, so you can use values from request `params` without any problem. +For example: `pagy(some_scope, items: params[:items])` will work without any additional cleanup. +!!! -A few variables are particularly important for the calculation of the pagination, and therefore are validated and used to -initialize a few instance variables. +### Variables The only mandatory instance variable to be passed is the `:count` of the collection to paginate: all the other variables are optional and have sensible defaults. Of course you will also have to pass the `page` or you will always get the default page number 1. -They are all integers: - -| Variable | Description | Default | -|:----------|:-----------------------------------------------------------------------------------------------|:--------| -| `:count` | The total count of the collection to paginate (mandatory argument) | `nil` | -| `:page` | The requested page number | `1` | -| `:items` | The requested number of items for the page | `20` | -| `:outset` | The initial offset of the collection to paginate: pass it only if the collection had an offset | `0` | - -### Other Variables - -| Variable | Description | Default | -|:-----------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------| -| `:size` | The size of the page links to show: can be an array of initial pages, before current page, after current page, final pages or the total page size. _(see also [How to control the page links](/docs/how-to.md#control-the-page-links))_ | `7` | -| `:page_param` | The name of the page param name used in the url. _(see [How to customize the page param](/docs/how-to.md#customize-the-page-param))_ | `:page` | -| `:params` | It can be a `Hash` of params to add to the URL, or a `Proc` that can edit/add/delete the request params _(see [How to customize the params](/docs/how-to.md#customize-the-params))_ | `{}` | -| `:fragment` | The arbitrary fragment string (including the "#") to add to the url. _(see [How to customize the params](/docs/how-to.md#customize-the-params))_ | `nil` | -| `:anchor_string` | The extra attributes string (formatted as a valid HTML attribute/value pairs) added to the page links _(see [How to customize the link attributes](/docs/how-to.md#customize-the-link-attributes))_ | `nil` | -| `:cycle` | Enable cycling/circular/infinite pagination: `true` sets `next` to `1` when the current page is the last page | `false` | -| `:request_path` | Allows overriding the request path for pagination links. Pass the path only (not the absolute url). _(see [Customize the request path](/docs/how-to.md#customize-the-request-path))_ | `nil` | -| `jsonapi` | Enable `jsonapi` compliance of the pagy query params | `false` | -| `count_args` | The arguments passed to the `collection.count`. You may want to set it to `[]` in ORMs different than ActiveRecord | [:all] | - -There is no specific validation for non-instance variables. + +| Variable | Description | Default | +|:-----------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------| +| `:anchor_string` | The extra attributes string (formatted as a valid HTML attribute/value pairs) added to the page links _(see [Customize the link attributes](/docs/how-to.md#customize-the-link-attributes))_ | `nil` | +| `:count` | The total count of the collection to paginate (mandatory argument) | `nil` | +| `:count_args` | The arguments passed to the `collection.count`. You may want to set it to `[]` in ORMs different than ActiveRecord | [:all] | +| `:cycle` | Enable cycling/circular/infinite pagination: `true` sets `next` to `1` when the current page is the last page | `false` | +| `:fragment` | The arbitrary fragment string (including the "#") to add to the url. _(see [Customize the params](/docs/how-to.md#customize-the-params))_ | `nil` | +| `:items` | The requested number of items for the page | `20` | +| `:jsonapi` | Enable `jsonapi` compliance of the pagy query params | `false` | +| `:max_pages` | Paginate only `:max_pages`. _(see also [Paginate only max_pages](/docs/how-to.md#paginate-only-max_pages-regardless-the-count))_ | `nil` | +| `:outset` | The initial offset of the collection to paginate: pass it only if the collection had an offset | `0` | +| `:page` | The requested page number: extracted from the `request.params`, or forced by passeing a variable | `1` | +| `:page_param` | The name of the page param name used in the url. _(see [Customize the page param](/docs/how-to.md#customize-the-page-param))_ | `:page` | +| `:params` | It can be a `Hash` of params to add to the URL, or a `Proc` that can edit/add/delete the request params _(see [Customize the params](/docs/how-to.md#customize-the-params))_ | `{}` | +| `:request_path` | Allows overriding the request path for pagination links. Pass the path only (not the absolute url). _(see [Customize the request path](/docs/how-to.md#customize-the-request-path))_ | `nil` | +| `:size` | The size of the page links to show: can be an array of 4 items or the integer of the total page size. _(see also [Control the page links](/docs/how-to.md#control-the-page-links))_ | `7` | + +!!! +Extras may add and document their own variables +!!! ### Attribute Readers @@ -164,19 +160,19 @@ or `nil`), except the `vars` hash: | Reader | Description | |:---------------|:-------------------------------------------------------------------------------------------------------------------| | `count` | The collection `:count` | -| `page` | The current page number | -| `items` | The requested number of items for the page | +| `from` | The collection-position of the first item in the page (`:outset` excluded) | | `in` | The number of the items in the page | +| `items` | The requested number of items for the page | | `last` | The number of the last page in the collection (ordinal meaning) | -| `pages` | Alias for `last` (cardinal meaning) | -| `offset` | The number of items skipped from the collection in order to get the start of the current page (`:outset` included) | -| `from` | The collection-position of the first item in the page (`:outset` excluded) | -| `to` | The collection-position of the last item in the page (`:outset` excluded) | -| `prev` | The previous page number or `nil` if there is no previous page | | `next` | The next page number or `nil` if there is no next page | -| `vars` | The variables hash | +| `offset` | The number of items skipped from the collection in order to get the start of the current page (`:outset` included) | +| `page` | The current page number | +| `pages` | Alias for `last` (cardinal meaning) | | `params` | The `:params` variable (`Hash` or `Proc`) | +| `prev` | The previous page number or `nil` if there is no previous page | | `request_path` | The request path used for pagination helpers. If nil, helpers will use `request.path` | +| `to` | The collection-position of the last item in the page (`:outset` excluded) | +| `vars` | The variables hash | ### Lowest limit analysis @@ -203,7 +199,7 @@ Which means: With `size: []` the `series` method returns `[]` - `in`, `from` and `to` of an empty page are all `0` - `prev` and `next` of a single page (not necessary an empty one) are both `nil` (i.e. there is no other page) - + === ## Exceptions diff --git a/docs/how-to.md b/docs/how-to.md index 7bfe8832d..2061a8440 100644 --- a/docs/how-to.md +++ b/docs/how-to.md @@ -41,7 +41,7 @@ See also a couple of extras that handle the `:items` in some special way: ## Control the page links -You can control the number and position of the page links in the navigation through the `:size` variable or override the +You can control the number and position of the page links in the navigation through the `:size` variable or override the `series` method. ==- Simple nav @@ -196,7 +196,7 @@ Pagy::DEFAULT[:anchor_string] = 'data-remote="true"' pagy = Pagy.new(count: 1000, anchor_string: 'data-remote="true"') # or from a view: e.g.: -<%== pagy_bootstrap_nav(@pagy, anchor_string: 'data-action="hello#world"') %> +< %== pagy_bootstrap_nav(@pagy, anchor_string: 'data-action="hello#world"') % > ``` _See more advanced details about [The anchor_string variable](api/frontend.md#the-anchor_string-variable)_ @@ -221,7 +221,7 @@ You can also use the `:fragment` variable to add a fragment the URLs of the page @pagy, @records = pagy(collection, fragment: '#your-fragment') ``` -!!!warning +!!!warning For performance reasons the `:fragment` string must include the `"#"`! !!! @@ -276,6 +276,7 @@ For a broader tutorial about this topic see [Handling Pagination When POSTing Complex Search Forms](https://benkoshy.github.io/2019/10/09/paginating-search-results-with-a-post-request.html) by Ben Koshy. === + ## Customize the item name The `pagy_info` and the `pagy_items_selector_js` helpers use the "item"/"items" generic name in their output. You can change that @@ -353,7 +354,7 @@ See the [array](extras/array.md) extra. ## Paginate ActiveRecord collections -Pagy works out of the box with `ActiveRecord` collections, however here are a few specific cases that might be treated +Pagy works out of the box with `ActiveRecord` collections, however here are a few specific cases that might be treated differently: ==- Grouped collection @@ -390,7 +391,7 @@ Ransack `result` returns an `ActiveRecord` collection, which can be paginated ou q = Person.ransack(params[:q]) @pagy, @people = pagy(q.result) ``` - + ==- PostgreSQL Collections [Always order your colections!](troubleshooting.md#records-may-randomly-repeat-in-different-pages-or-be-missing) @@ -440,7 +441,7 @@ day). By default pagy tries to derive parameters and variables from the request and the collection, so you don't have to explicitly pass it to the `pagy*` method. That is very handy, but assumes you are paginating a single collection per request. -When you need to paginate multiple collections in a single request, you need to explicitly differentiate the pagination +When you need to paginate multiple collections in a single request, you need to explicitly differentiate the pagination objects. You have the following commong ways to do so: ==- Pass the request path @@ -570,9 +571,35 @@ to different existing statements. ``` Then follow the [calendar extra documentation](extras/calendar.md) for more details. - + === +## Paginate only max_pages, regardless the count + +In order to limit the pagination to a maximum number of pages, you can pass the `:max_pages` variable. + +For example: + +```ruby +@pagy, @records = pagy(scope, max_pages: 50, items: 20) +@records.size #=> 20 +@pagy.count #=> 10_000 +@pagy.last #=> 50 + +@pagy, @records = pagy(scope, max_pages: 50, items: 20, page: 51) +#=> Pagy::OverflowError: expected :page in 1..50; got 51 +``` + +If the `@pagy.count` in the example is `10_000`, the pages served without `:max_pages` would be `500`, but with +`:max_pages: 50` pagy would serve only the first `50` pages of your collection. + +That works at the `Pagy`/`Pagy::Countless` level, so it works with any combination of collection/extra, including `items`, +`gearbox` and search extras. + +!!! Notice +The `items` and `gearbox` extras serve a variabe number of items per page. If your goal is limiting the pagination to a max number of records (instead of pages), you have to keep into account how you configure the `items` range. +!!! + ## Paginate pre-offset and pre-limited collections With the other pagination gems you cannot paginate a subset of a collection that you got using `offset` and `limit`. With Pagy it @@ -669,7 +696,7 @@ ready to use in your view. For example: ``` !!!primary Extras Provide Added Functionality -The [frontend extras](/categories/frontend) add a few other helpers that you can use the same way, in order to get added features +The [frontend extras](/categories/frontend) add a few other helpers that you can use the same way, in order to get added features !!! ## Skip single page navs @@ -842,7 +869,7 @@ standards. Using your own templates is possible, but it's likely just reinventin !!! If you really need to use your own templates, you absolutely can. Here is a static example that doesn't use any other helper nor -dictionary file for the sake of simplicity, however feel free to add your dynamic variables and use any helper and dictionary +dictionary file for the sake of simplicity, however feel free to add your dynamic variables and use any helper and dictionary entries as you need: :::code source="assets/nav.html.erb" ::: @@ -855,10 +882,12 @@ You can use it as usual: just remember to pass the `:pagy` local set to the `@pa !!! You may want to look at the actual output interactively by running: + ```sh pagy demo # or: bundle exec pagy demo ``` + ...and point your browser at http://0.0.0.0:8000/template !!! diff --git a/gem/lib/pagy.rb b/gem/lib/pagy.rb index 79f0093f2..bd4b008ef 100644 --- a/gem/lib/pagy.rb +++ b/gem/lib/pagy.rb @@ -31,10 +31,11 @@ def initialize(vars) setup_vars(count: 0, page: 1, outset: 0) setup_items_var setup_last_var + raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last + setup_offset_var setup_params_var setup_request_path_var - raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last @from = [@offset - @outset + 1, @count].min @to = [@offset - @outset + @items, @count].min @@ -118,6 +119,7 @@ def setup_items_var # Setup @last and @last (overridden by the gearbox extra) def setup_last_var @last = [(@count.to_f / @items).ceil, 1].max + @last = vars[:max_pages] if vars[:max_pages] && @last > vars[:max_pages] end alias setup_pages_var setup_last_var diff --git a/gem/lib/pagy/countless.rb b/gem/lib/pagy/countless.rb index 3fb99f2d3..cf2389bf3 100644 --- a/gem/lib/pagy/countless.rb +++ b/gem/lib/pagy/countless.rb @@ -19,7 +19,10 @@ def initialize(vars = {}) # rubocop:disable Lint/MissingSuper def finalize(fetched_size) raise OverflowError.new(self, :page, "to be < #{@page}", @page) if fetched_size.zero? && @page > 1 - @last = (fetched_size > @items ? @page + 1 : @page) + @last = fetched_size > @items ? @page + 1 : @page + @last = vars[:max_pages] if vars[:max_pages] && @last > vars[:max_pages] + raise OverflowError.new(self, :page, "in 1..#{@last}", @page) if @page > @last + @in = [fetched_size, @items].min @from = @in.zero? ? 0 : @offset - @outset + 1 @to = @offset - @outset + @in diff --git a/gem/lib/pagy/extras/gearbox.rb b/gem/lib/pagy/extras/gearbox.rb index 374f70e4b..78f645144 100644 --- a/gem/lib/pagy/extras/gearbox.rb +++ b/gem/lib/pagy/extras/gearbox.rb @@ -12,42 +12,43 @@ module GearboxExtra def setup_items_var return super if !@vars[:gearbox_extra] || @vars[:items_extra] - gearbox_items = @vars[:gearbox_items] - raise VariableError.new(self, :gearbox_items, 'to be an Array of positives', gearbox_items) \ - unless gearbox_items.is_a?(Array) && gearbox_items.all? { |num| num.positive? rescue false } # rubocop:disable Style/RescueModifier + gears = @vars[:gearbox_items] + raise VariableError.new(self, :gearbox_items, 'to be an Array of positives', gears) \ + unless gears.is_a?(Array) && gears.all? { |num| num.positive? rescue false } # rubocop:disable Style/RescueModifier - @items = gearbox_items[@page - 1] || gearbox_items.last + @items = gears[@page - 1] || gears.last end - # Setup @last based on the :gearbox_items variable (not used by Pagy::Countless) + # Setup Pagy @last based on the :gearbox_items variable and @count def setup_last_var return super if !@vars[:gearbox_extra] || @vars[:items_extra] - gearbox_items = @vars[:gearbox_items] + gears = @vars[:gearbox_items] # This algorithm is thousands of times faster than the one in the geared_pagination gem - @last = (if @count > (sum = gearbox_items.sum) - [((@count - sum).to_f / gearbox_items.last).ceil, 1].max + gearbox_items.count + @last = (if count > (sum = gears.sum) + [((count - sum).to_f / gears.last).ceil, 1].max + gears.count else pages = 0 - remainder = @count + remainder = count while remainder.positive? pages += 1 - remainder -= gearbox_items[pages - 1] + remainder -= gears[pages - 1] end [pages, 1].max end) + @last = vars[:max_pages] if vars[:max_pages] && @last > vars[:max_pages] end # Setup @offset based on the :gearbox_items variable def setup_offset_var return super if !@vars[:gearbox_extra] || @vars[:items_extra] - gearbox_items = @vars[:gearbox_items] - @offset = if @page <= gearbox_items.count - gearbox_items[0, @page - 1].sum - else - gearbox_items.sum + (gearbox_items.last * (@page - gearbox_items.count - 1)) - end + @outset + gears = @vars[:gearbox_items] + @offset = if @page <= gears.count + gears[0, @page - 1].sum + else + gears.sum + (gears.last * (@page - gears.count - 1)) + end + @outset end end prepend GearboxExtra diff --git a/test/pagy/extras/gearbox_test.rb b/test/pagy/extras/gearbox_test.rb index b7b271341..0eb142231 100644 --- a/test/pagy/extras/gearbox_test.rb +++ b/test/pagy/extras/gearbox_test.rb @@ -52,18 +52,31 @@ end describe '#setup_last_var' do - it 'can skip gearbox for pages' do - _(Pagy.new(count: 90, page: 1, items_extra: true).pages).must_equal 5 - _(Pagy.new(count: 103, page: 1, gearbox_extra: false).pages).must_equal 6 + it 'can skip gearbox for last' do + _(Pagy.new(count: 90, page: 1, items_extra: true).last).must_equal 5 + _(Pagy.new(count: 103, page: 1, gearbox_extra: false).last).must_equal 6 end - it 'sets the pages' do - _(Pagy.new(count: 0, page: 1, gearbox_items: [3, 10]).pages).must_equal 1 - _(Pagy.new(count: 3, page: 1, gearbox_items: [3, 10]).pages).must_equal 1 - _(Pagy.new(count: 13, page: 2, gearbox_items: [3, 10]).pages).must_equal 2 - _(Pagy.new(count: 103, page: 1, gearbox_items: [3, 10]).pages).must_equal 11 - _(Pagy.new(count: 103, page: 2, gearbox_items: [3, 10]).pages).must_equal 11 - _(Pagy.new(count: 103, page: 3, gearbox_items: [3, 10]).pages).must_equal 11 - _(Pagy.new(count: 103, page: 11, gearbox_items: [3, 10]).pages).must_equal 11 + it 'sets the last' do + _(Pagy.new(count: 0, page: 1, gearbox_items: [3, 10]).last).must_equal 1 + _(Pagy.new(count: 3, page: 1, gearbox_items: [3, 10]).last).must_equal 1 + _(Pagy.new(count: 13, page: 2, gearbox_items: [3, 10]).last).must_equal 2 + _(Pagy.new(count: 103, page: 1, gearbox_items: [3, 10]).last).must_equal 11 + _(Pagy.new(count: 103, page: 2, gearbox_items: [3, 10]).last).must_equal 11 + _(Pagy.new(count: 103, page: 3, gearbox_items: [3, 10]).last).must_equal 11 + _(Pagy.new(count: 103, page: 11, gearbox_items: [3, 10]).last).must_equal 11 + # max_pages + _(Pagy.new(count: 24, page: 2, gearbox_items: [3, 10], max_pages: 2).last).must_equal 2 + _ { Pagy.new(count: 24, page: 3, gearbox_items: [3, 10], max_pages: 2) }.must_raise Pagy::OverflowError + + end + it "checks the last in Pagy::Countless" do + _(Pagy::Countless.new(page: 1, gearbox_items: [3, 10]).finalize(2).last).must_equal 1 + _(Pagy::Countless.new(page: 1, gearbox_items: [3, 10]).finalize(4).last).must_equal 2 + _(Pagy::Countless.new(page: 3, gearbox_items: [3, 10]).finalize(7).last).must_equal 3 + _(Pagy::Countless.new(page: 3, gearbox_items: [3, 10]).finalize(11).last).must_equal 4 + # max_pages + _(Pagy::Countless.new(page: 2, gearbox_items: [3, 10], max_pages: 2).finalize(11).last).must_equal 2 + _ { Pagy::Countless.new(page: 3, gearbox_items: [3, 10], max_pages: 2).finalize(11) }.must_raise Pagy::OverflowError end end diff --git a/test/pagy_test.rb b/test/pagy_test.rb index 42ce5fa3c..243441aa6 100644 --- a/test/pagy_test.rb +++ b/test/pagy_test.rb @@ -299,9 +299,15 @@ def series_for(page, *expected) end it 'handles the :cycle variable' do pagy = Pagy.new(count: 100, page: 10, items: 10, cycle: true) - _(pagy.prev).must_equal(9) + _(pagy.prev).must_equal 9 _(pagy.next).must_equal 1 end + it 'handles the :ma_pages variable' do + pagy = Pagy.new(count: 100, page: 3, items: 10, max_pages: 8) + _(pagy.count).must_equal 100 + _(pagy.last).must_equal 8 + _ { Pagy.new(count: 100, page: 9, items: 10, max_pages: 8) }.must_raise Pagy::OverflowError + end it 'initializes the request_path' do pagy = Pagy.new(count: 100, request_path: '/foo') _(pagy.vars[:request_path]).must_equal('/foo') From 8cd0e9650a7c51a582f3255d88fe31df0576aa70 Mon Sep 17 00:00:00 2001 From: Domizio Demichelis Date: Tue, 9 Apr 2024 08:24:12 +0700 Subject: [PATCH 10/11] Update rubocop --- Gemfile.lock | 2 +- gem/lib/pagy/calendar.rb | 2 +- test/pagy/extras/gearbox_test.rb | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index c088f753e..3df2786c5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -88,7 +88,7 @@ GEM listen (~> 3.0) rexml (3.2.6) rouge (4.2.1) - rubocop (1.62.1) + rubocop (1.63.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) diff --git a/gem/lib/pagy/calendar.rb b/gem/lib/pagy/calendar.rb index 53a618c74..d9827a871 100644 --- a/gem/lib/pagy/calendar.rb +++ b/gem/lib/pagy/calendar.rb @@ -74,7 +74,7 @@ def page_at(time, **opts) def setup_unit_vars raise VariableError.new(self, :format, 'to be a strftime format', @vars[:format]) unless @vars[:format].is_a?(String) raise VariableError.new(self, :order, 'to be in [:asc, :desc]', @order) \ - unless %i[asc desc].include?(@order = @vars[:order]) + unless %i[asc desc].include?((@order = @vars[:order])) @starting, @ending = @vars[:period] raise VariableError.new(self, :period, 'to be a an Array of min and max TimeWithZone instances', @vars[:period]) \ diff --git a/test/pagy/extras/gearbox_test.rb b/test/pagy/extras/gearbox_test.rb index 0eb142231..e53b76d75 100644 --- a/test/pagy/extras/gearbox_test.rb +++ b/test/pagy/extras/gearbox_test.rb @@ -67,7 +67,6 @@ # max_pages _(Pagy.new(count: 24, page: 2, gearbox_items: [3, 10], max_pages: 2).last).must_equal 2 _ { Pagy.new(count: 24, page: 3, gearbox_items: [3, 10], max_pages: 2) }.must_raise Pagy::OverflowError - end it "checks the last in Pagy::Countless" do _(Pagy::Countless.new(page: 1, gearbox_items: [3, 10]).finalize(2).last).must_equal 1 From 79dd031bc27ad57e553a6df8419b91d683f5214d Mon Sep 17 00:00:00 2001 From: Domizio Demichelis Date: Tue, 9 Apr 2024 08:30:17 +0700 Subject: [PATCH 11/11] Version 8.1.0 --- .github/ISSUE_TEMPLATE/Code.yml | 2 +- .github/latest_release_body.md | 15 ++++++--------- CHANGELOG.md | 7 +++++++ README.md | 2 +- gem/apps/calendar.ru | 2 +- gem/apps/demo.ru | 2 +- gem/apps/rails.ru | 2 +- gem/apps/repro.ru | 2 +- gem/bin/pagy | 2 +- gem/config/pagy.rb | 2 +- gem/javascripts/pagy-dev.js | 4 ++-- gem/javascripts/pagy-module.js | 2 +- gem/javascripts/pagy.js | 2 +- gem/lib/pagy.rb | 2 +- quick-start.md | 2 +- retype.yml | 2 +- src/pagy.ts | 2 +- 17 files changed, 29 insertions(+), 25 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/Code.yml b/.github/ISSUE_TEMPLATE/Code.yml index d79bd6592..8d3c68405 100644 --- a/.github/ISSUE_TEMPLATE/Code.yml +++ b/.github/ISSUE_TEMPLATE/Code.yml @@ -19,7 +19,7 @@ body: attributes: label: Before submitting... options: - - label: I upgraded to pagy version 8.0.2 + - label: I upgraded to pagy version 8.1.0 required: true - label: I searched through the [Documentation](https://ddnexus.github.io/pagy/) required: true diff --git a/.github/latest_release_body.md b/.github/latest_release_body.md index b1689d802..55c622bdd 100644 --- a/.github/latest_release_body.md +++ b/.github/latest_release_body.md @@ -7,21 +7,18 @@ If you wish to keep your favorites alive, please, [vote here](https://github.com ### ✴ What's new in 8.+ ✴ - Better frontend helpers +- New `:max_pages` variable to limit the pagination regardless the actual count - New [Pagy Playground](https://ddnexus.github.io/pagy/playground/) to showcase, clone and develop pagy APPs without any setup on your side (try the [pagy demo](https://ddnexus.github.io/pagy/playground.md#3-demo-app)) - See the [CHANGELOG](https://ddnexus.github.io/pagy/changelog) for possible breaking changes -### Changes in 8.0.2 +### Changes in 8.1.0 -- Minor change in rails app and RM run config -- Fix canonical gem root: - - Correct script.build: "NODE_PATH=\"$(bundle show 'pagy')/javascripts\" - - Move pagy.gemspec inside the gem root dir -- Fix for Turbo not intercepting changes in window.location -- Use require_relative for gem/lib files -- Complete translation of aria.nav for "ru" locale (close #599) -- Docs improvement and fixes +- Implement max_pages to limit the pagination regardless the actual count +- Improve efficiency of params in pagy_url_for +- Remove nil variables from DEFAULT +- Removed redundant @pages, aliased with @last [CHANGELOG](https://ddnexus.github.io/pagy/changelog) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29b7ef3c0..d3e04b944 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,13 @@ If you upgrade from version `< 8.0.0` see the following:
+## Version 8.1.0 + +- Implement max_pages to limit the pagination regardless the actual count +- Improve efficiency of params in pagy_url_for +- Remove nil variables from DEFAULT +- Removed redundant @pages, aliased with @last + ## Version 8.0.2 - Minor change in rails app and RM run config diff --git a/README.md b/README.md index 5a8e18863..bd56d93a5 100644 --- a/README.md +++ b/README.md @@ -371,7 +371,7 @@ See also the [How To Page](https://ddnexus.github.io/pagy/docs/how-to) ## Top 💯 Contributors -[](https://github.com/ddnexus)[](https://github.com/benkoshy)[](https://github.com/dependabot[bot])[](https://github.com/grosser)[](https://github.com/Earlopain)[](https://github.com/workgena)[](https://github.com/bquorning)[](https://github.com/molfar)[](https://github.com/sunny)[](https://github.com/enzinia)[](https://github.com/espen)[](https://github.com/berniechiu)[](https://github.com/renshuki)[](https://github.com/wimdavies)[](https://github.com/tiagotex)[](https://github.com/gamafranco)[](https://github.com/thomasklemm)[](https://github.com/tersor)[](https://github.com/simonneutert)[](https://github.com/rainerborene)[](https://github.com/petergoldstein)[](https://github.com/sabljak)[](https://github.com/cseelus)[](https://github.com/ashmaroli)[](https://github.com/747)[](https://github.com/WilliamHorel)[](https://github.com/okuramasafumi)[](https://github.com/olleolleolle)[](https://github.com/pedrocarmona)[](https://github.com/rafaeelaudibert)[](https://github.com/rafaelmontas)[](https://github.com/yenshirak)[](https://github.com/Tolchi)[](https://github.com/serghost)[](https://github.com/sliminas)[](https://github.com/artplan1)[](https://github.com/woller)[](https://github.com/sk8higher)[](https://github.com/muhammadnawzad)[](https://github.com/ronald)[](https://github.com/achmiral)[](https://github.com/mauro-ni)[](https://github.com/borama)[](https://github.com/creativetags)[](https://github.com/mcary)[](https://github.com/marckohlbrugge)[](https://github.com/tr4b4nt)[](https://github.com/tiejianluo)[](https://github.com/szTheory)[](https://github.com/smoothdvd)[](https://github.com/rhodes-david)[](https://github.com/radinreth)[](https://github.com/okliv)[](https://github.com/nedimdz)[](https://github.com/msdundar)[](https://github.com/m-abdurrehman)[](https://github.com/dwieringa)[](https://github.com/jyuvaraj03)[](https://github.com/YutoYasunaga)[](https://github.com/iamyujinwon)[](https://github.com/yhk1038)[](https://github.com/ya-s-u)[](https://github.com/yshmarov)[](https://github.com/thattimc)[](https://github.com/thomaschauffour)[](https://github.com/snkashis)[](https://github.com/fluser)[](https://github.com/tulak)[](https://github.com/Federico-G)[](https://github.com/egimenos)[](https://github.com/elliotlarson)[](https://github.com/hungdiep97)[](https://github.com/djpremier)[](https://github.com/davidwessman)[](https://github.com/david-a-wheeler)[](https://github.com/MrMoins)[](https://github.com/excid3)[](https://github.com/cellvinchung)[](https://github.com/brunoocasali)[](https://github.com/BrandonKlotz)[](https://github.com/Atul9)[](https://github.com/amenon)[](https://github.com/artinboghosian)[](https://github.com/antonzaharia)[](https://github.com/andrew)[](https://github.com/AliOsm)[](https://github.com/AbelToy)[](https://github.com/maful)[](https://github.com/loed-idzinga)[](https://github.com/epeirce)[](https://github.com/kobusjoubert)[](https://github.com/KevinColemanInc)[](https://github.com/neontuna)[](https://github.com/xuanxu)[](https://github.com/jpgarritano)[](https://github.com/archonic)[](https://github.com/jonasMirendo)[](https://github.com/lostapathy)[](https://github.com/jivko-chobanov)[](https://github.com/whithajess) +[](https://github.com/ddnexus)[](https://github.com/benkoshy)[](https://github.com/dependabot[bot])[](https://github.com/grosser)[](https://github.com/Earlopain)[](https://github.com/workgena)[](https://github.com/bquorning)[](https://github.com/molfar)[](https://github.com/sunny)[](https://github.com/enzinia)[](https://github.com/espen)[](https://github.com/berniechiu)[](https://github.com/renshuki)[](https://github.com/wimdavies)[](https://github.com/tiagotex)[](https://github.com/gamafranco)[](https://github.com/thomasklemm)[](https://github.com/tersor)[](https://github.com/simonneutert)[](https://github.com/rainerborene)[](https://github.com/petergoldstein)[](https://github.com/sabljak)[](https://github.com/cseelus)[](https://github.com/ashmaroli)[](https://github.com/747)[](https://github.com/WilliamHorel)[](https://github.com/okuramasafumi)[](https://github.com/olleolleolle)[](https://github.com/pedrocarmona)[](https://github.com/rafaeelaudibert)[](https://github.com/rafaelmontas)[](https://github.com/yenshirak)[](https://github.com/Tolchi)[](https://github.com/serghost)[](https://github.com/sliminas)[](https://github.com/artplan1)[](https://github.com/woller)[](https://github.com/sk8higher)[](https://github.com/muhammadnawzad)[](https://github.com/ronald)[](https://github.com/achmiral)[](https://github.com/mauro-ni)[](https://github.com/borama)[](https://github.com/creativetags)[](https://github.com/mcary)[](https://github.com/marckohlbrugge)[](https://github.com/tr4b4nt)[](https://github.com/tiejianluo)[](https://github.com/szTheory)[](https://github.com/smoothdvd)[](https://github.com/rhodes-david)[](https://github.com/radinreth)[](https://github.com/okliv)[](https://github.com/nedimdz)[](https://github.com/msdundar)[](https://github.com/m-abdurrehman)[](https://github.com/dwieringa)[](https://github.com/jyuvaraj03)[](https://github.com/YutoYasunaga)[](https://github.com/iamyujinwon)[](https://github.com/yhk1038)[](https://github.com/ya-s-u)[](https://github.com/yshmarov)[](https://github.com/thattimc)[](https://github.com/thomaschauffour)[](https://github.com/snkashis)[](https://github.com/fluser)[](https://github.com/tulak)[](https://github.com/Federico-G)[](https://github.com/egimenos)[](https://github.com/elliotlarson)[](https://github.com/hungdiep97)[](https://github.com/djpremier)[](https://github.com/davidwessman)[](https://github.com/david-a-wheeler)[](https://github.com/MrMoins)[](https://github.com/excid3)[](https://github.com/cellvinchung)[](https://github.com/brunoocasali)[](https://github.com/BrandonKlotz)[](https://github.com/Atul9)[](https://github.com/amenon)[](https://github.com/artinboghosian)[](https://github.com/antonzaharia)[](https://github.com/andrew)[](https://github.com/AliOsm)[](https://github.com/AbelToy)[](https://github.com/maful)[](https://github.com/loed-idzinga)[](https://github.com/epeirce)[](https://github.com/kobusjoubert)[](https://github.com/KevinColemanInc)[](https://github.com/neontuna)[](https://github.com/xuanxu)[](https://github.com/jpgarritano)[](https://github.com/archonic)[](https://github.com/jonasMirendo)[](https://github.com/lostapathy)[](https://github.com/jivko-chobanov)[](https://github.com/whithajess)
diff --git a/gem/apps/calendar.ru b/gem/apps/calendar.ru index 909f7bbd7..8d5bc71fe 100644 --- a/gem/apps/calendar.ru +++ b/gem/apps/calendar.ru @@ -18,7 +18,7 @@ # DOC # https://ddnexus.github.io/pagy/playground/#4-calendar-app -VERSION = '8.0.2' +VERSION = '8.1.0' require 'bundler/inline' gemfile(true) do diff --git a/gem/apps/demo.ru b/gem/apps/demo.ru index b8f636230..a1973474a 100644 --- a/gem/apps/demo.ru +++ b/gem/apps/demo.ru @@ -18,7 +18,7 @@ # DOC # https://ddnexus.github.io/pagy/playground/#3-demo-app -VERSION = '8.0.2' +VERSION = '8.1.0' require 'bundler/inline' gemfile(true) do diff --git a/gem/apps/rails.ru b/gem/apps/rails.ru index 50debd6b6..b8d632c13 100644 --- a/gem/apps/rails.ru +++ b/gem/apps/rails.ru @@ -15,7 +15,7 @@ # DOC # https://ddnexus.github.io/pagy/playground/#2-rails-app -VERSION = '8.0.2' +VERSION = '8.1.0' # Gemfile require 'bundler/inline' diff --git a/gem/apps/repro.ru b/gem/apps/repro.ru index d5ee91529..5a19e5bfa 100644 --- a/gem/apps/repro.ru +++ b/gem/apps/repro.ru @@ -15,7 +15,7 @@ # DOC # https://ddnexus.github.io/pagy/playground/#1-repro-app -VERSION = '8.0.2' +VERSION = '8.1.0' require 'bundler/inline' gemfile(true) do diff --git a/gem/bin/pagy b/gem/bin/pagy index ce2216cce..6a106a6ad 100755 --- a/gem/bin/pagy +++ b/gem/bin/pagy @@ -1,7 +1,7 @@ #!/usr/bin/env ruby # frozen_string_literal: true -VERSION = '8.0.2' +VERSION = '8.1.0' APPS = %w[repro rails demo calendar].freeze require_relative '../lib/optimist' diff --git a/gem/config/pagy.rb b/gem/config/pagy.rb index 79b754385..34284c091 100644 --- a/gem/config/pagy.rb +++ b/gem/config/pagy.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -# Pagy initializer file (8.0.2) +# Pagy initializer file (8.1.0) # Customize only what you really need and notice that the core Pagy works also without any of the following lines. # Should you just cherry pick part of this file, please maintain the require-order of the extras diff --git a/gem/javascripts/pagy-dev.js b/gem/javascripts/pagy-dev.js index dadfd4398..5f12ca6d5 100644 --- a/gem/javascripts/pagy-dev.js +++ b/gem/javascripts/pagy-dev.js @@ -82,7 +82,7 @@ window.Pagy = (() => { const trim = (a, param) => a.replace(new RegExp(`[?&]${param}=1\\b(?!&)|\\b${param}=1&`), ""); // Public interface return { - version: "8.0.2", + version: "8.1.0", // Scan for elements with a "data-pagy" attribute and call their init functions with the decoded args init(arg) { const target = arg instanceof Element ? arg : document; @@ -111,4 +111,4 @@ window.Pagy = (() => { } }; })(); -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFneS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInBhZ3kudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQWtCQSxNQUFNLElBQUksR0FBRyxDQUFDLEdBQUcsRUFBRTtJQUNmLDRDQUE0QztJQUM1QyxNQUFNLFdBQVcsR0FBRyxJQUFJLGNBQWMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUNOLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFhLFdBQVcsQ0FBQyxDQUFDLE9BQU8sQ0FDM0UsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFeEUsNEJBQTRCO0lBQzVCLE1BQU0sT0FBTyxHQUFHLENBQUMsRUFBYSxFQUFFLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsU0FBUyxDQUFTLEVBQUUsRUFBRTtRQUNsRixNQUFNLFNBQVMsR0FBRyxFQUFFLENBQUMsYUFBYSxJQUFJLEVBQUUsQ0FBQztRQUN6QyxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNoRixJQUFJLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNuQixNQUFNLE1BQU0sR0FBRyxDQUFDLENBQVEsRUFBRSxJQUFXLEVBQUUsS0FBWSxFQUFTLEVBQUUsQ0FDMUQsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUMsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDeEUsQ0FBQyxFQUFFLENB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TyxHQUFHLEVBQUUsQ0FBQztvQkFBQyxPQUFPLENBQUMsSUFBSSxDQUFDLGlDQUFpQyxFQUFFLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQTtnQkFBQyxDQUFDO1lBQzlFLENBQUM7UUFDTCxDQUFDO0tBQ0osQ0FBQztBQUNOLENBQUMsQ0FBQyxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJ0eXBlIE5hdkFyZ3MgPSByZWFkb25seSBbVG9rZW5zLCBTZXF1ZWxzLCBudWxsIHwgTGFiZWxTZXF1ZWxzLCBzdHJpbmc/XVxudHlwZSBDb21ib0FyZ3MgPSByZWFkb25seSBbc3RyaW5nLCBzdHJpbmc/XVxudHlwZSBTZWxlY3RvckFyZ3MgPSByZWFkb25seSBbbnVtYmVyLCBzdHJpbmcsIHN0cmluZz9dXG5cbmludGVyZmFjZSBUb2tlbnMge1xuICAgIHJlYWRvbmx5IGJlZm9yZTpzdHJpbmdcbiAgICByZWFkb25seSBhOnN0cmluZ1xuICAgIHJlYWRvbmx5IGN1cnJlbnQ6c3RyaW5nXG4gICAgcmVhZG9ubHkgZ2FwOnN0cmluZ1xuICAgIHJlYWRvbmx5IGFmdGVyOnN0cmluZ1xufVxuXG5pbnRlcmZhY2UgU2VxdWVscyB7cmVhZG9ubHkgW3dpZHRoOnN0cmluZ106KHN0cmluZyB8IG51bWJlcilbXX1cblxuaW50ZXJmYWNlIExhYmVsU2VxdWVscyB7cmVhZG9ubHkgW3dpZHRoOnN0cmluZ106c3RyaW5nW119XG5cbmludGVyZmFjZSBOYXZFbGVtZW50IGV4dGVuZHMgRWxlbWVudCB7cGFneVJlbmRlcigpOnZvaWR9XG5cbmNvbnN0IFBhZ3kgPSAoKCkgPT4ge1xuICAgIC8vIFRoZSBvYnNlcnZlciBpbnN0YW5jZSBmb3IgcmVzcG9uc2l2ZSBuYXZzXG4gICAgY29uc3QgcmpzT2JzZXJ2ZXIgPSBuZXcgUmVzaXplT2JzZXJ2ZXIoZW50cmllcyA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnRyaWVzLmZvckVhY2goZSA9PiBlLnRhcmdldC5xdWVyeVNlbGVjdG9yQWxsPE5hdkVsZW1lbnQ+KFwiLnBhZ3ktcmpzXCIpLmZvckVhY2goXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbCA9PiBlbC5wYWd5UmVuZGVyKCkpKSk7XG5cbiAgICAvLyBJbml0IHRoZSAqX25hdl9qcyBoZWxwZXJzXG4gICAgY29uc3QgaW5pdE5hdiA9IChlbDpOYXZFbGVtZW50LCBbdG9rZW5zLCBzZXF1ZWxzLCBsYWJlbFNlcXVlbHMsIHRyaW1QYXJhbV06TmF2QXJncykgPT4ge1xuICAgICAgICBjb25zdCBjb250YWluZXIgPSBlbC5wYXJlbnRFbGVtZW50ID8/IGVsO1xuICAgICAgICBjb25zdCB3aWR0aHMgPSBPYmplY3Qua2V5cyhzZXF1ZWxzKS5tYXAodyA9PiBwYXJzZUludCh3KSkuc29ydCgoYSwgYikgPT4gYiAtIGEpO1xuICAgICAgICBsZXQgbGFzdFdpZHRoID0gLTE7XG4gICAgICAgIGNvbnN0IGZpbGxJbiA9IChhOnN0cmluZywgcGFnZTpzdHJpbmcsIGxhYmVsOnN0cmluZyk6c3RyaW5nID0+XG4gICAgICAgICAgICBhLnJlcGxhY2UoL19fcGFneV9wYWdlX18vZywgcGFnZSkucmVwbGFjZSgvX19wYWd5X2xhYmVsX18vZywgbGFiZWwpO1xuICAgICAgICAoZWwucGFneVJlbmRlciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGNvbnN0IHdpZHRoID0gd2lkdGhzLmZpbmQodyA9PiB3IDwgY29udGFpbmVyLmNsaWVudFdpZHRoKSB8fCAwO1xuICAgICAgICAgICAgaWYgKHdpZHRoID09PSBsYXN0V2lkdGgpIHsgcmV0dXJuIH0gLy8gbm8gY2hhbmdlOiBhYm9ydFxuICAgICAgICAgICAgbGV0IGh0bWwgPSB0b2tlbnMuYmVmb3JlOyAgLy8gYWxyZWFkeSB0cmltbWVkIGluIGh0bWxcbiAgICAgICAgICAgIGNvbnN0IHNlcmllcyA9IHNlcXVlbHNbd2lkdGgudG9TdHJpbmcoKV07XG4gICAgICAgICAgICBjb25zdCBsYWJlbHMgPSBsYWJlbFNlcXVlbHM/Llt3aWR0aC50b1N0cmluZygpXSA/PyBzZXJpZXMubWFwKGwgPT4gbC50b1N0cmluZygpKTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgaSBpbiBzZXJpZXMpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBpdGVtID0gc2VyaWVzW2ldO1xuICAgICAgICAgICAgICAgIGNvbnN0IGxhYmVsID0gbGFiZWxzW2ldO1xuICAgICAgICAgICAgICAgIGxldCBmaWxsZWQ7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpdGVtID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGZpbGxlZCA9IGZpbGxJbih0b2tlbnMuYSwgaXRlbS50b1N0cmluZygpLCBsYWJlbCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChpdGVtID09PSBcImdhcFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGZpbGxlZCA9IHRva2Vucy5nYXA7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHsgLy8gYWN0aXZlIHBhZ2VcbiAgICAgICAgICAgICAgICAgICAgZmlsbGVkID0gZmlsbEluKHRva2Vucy5jdXJyZW50LCBpdGVtLCBsYWJlbCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGh0bWwgKz0gKHR5cGVvZiB0cmltUGFyYW0gPT09IFwic3RyaW5nXCIgJiYgaXRlbSA9PSAxKSA/IHRyaW0oZmlsbGVkLCB0cmltUGFyYW0pIDogZmlsbGVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaHRtbCArPSB0b2tlbnMuYWZ0ZXI7ICAgLy8gZXNsaW50LWRpc2FibGUtbGluZSBhbGlnbi1hc3NpZ25tZW50cy9hbGlnbi1hc3NpZ25tZW50c1xuICAgICAgICAgICAgZWwuaW5uZXJIVE1MID0gXCJcIjtcbiAgICAgICAgICAgIGVsLmluc2VydEFkamFjZW50SFRNTChcImFmdGVyYmVnaW5cIiwgaHRtbCk7XG4gICAgICAgICAgICBsYXN0V2lkdGggPSB3aWR0aDtcbiAgICAgICAgfSkoKTtcbiAgICAgICAgaWYgKGVsLmNsYXNzTGlzdC5jb250YWlucyhcInBhZ3ktcmpzXCIpKSB7IHJqc09ic2VydmVyLm9ic2VydmUoY29udGFpbmVyKSB9XG4gICAgfTtcblxuICAgIC8vIEluaXQgdGhlICpfY29tYm9fbmF2X2pzIGhlbHBlcnNcbiAgICBjb25zdCBpbml0Q29tYm8gPSAoZWw6RWxlbWVudCwgW3VybF90b2tlbiwgdHJpbVBhcmFtXTpDb21ib0FyZ3MpID0+XG4gICAgICAgIGluaXRJbnB1dChlbCwgaW5wdXRWYWx1ZSA9PiBbaW5wdXRWYWx1ZSwgdXJsX3Rva2VuLnJlcGxhY2UoL19fcGFneV9wYWdlX18vLCBpbnB1dFZhbHVlKV0sIHRyaW1QYXJhbSk7XG5cbiAgICAvLyBJbml0IHRoZSBpdGVtc19zZWxlY3Rvcl9qcyBoZWxwZXJcbiAgICBjb25zdCBpbml0U2VsZWN0b3IgPSAoZWw6RWxlbWVudCwgW2Zyb20sIHVybF90b2tlbiwgdHJpbVBhcmFtXTpTZWxlY3RvckFyZ3MpID0+IHtcbiAgICAgICAgaW5pdElucHV0KGVsLCBpbnB1dFZhbHVlID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHBhZ2UgPSBNYXRoLm1heChNYXRoLmNlaWwoZnJvbSAvIHBhcnNlSW50KGlucHV0VmFsdWUpKSwgMSkudG9TdHJpbmcoKTtcbiAgICAgICAgICAgIGNvbnN0IHVybCA9IHVybF90b2tlbi5yZXBsYWNlKC9fX3BhZ3lfcGFnZV9fLywgcGFnZSkucmVwbGFjZSgvX19wYWd5X2l0ZW1zX18vLCBpbnB1dFZhbHVlKTtcbiAgICAgICAgICAgIHJldHVybiBbcGFnZSwgdXJsXTtcbiAgICAgICAgfSwgdHJpbVBhcmFtKTtcbiAgICB9O1xuXG4gICAgLy8gSW5pdCB0aGUgaW5wdXQgZWxlbWVudFxuICAgIGNvbnN0IGluaXRJbnB1dCA9IChlbDpFbGVtZW50LCBnZXRWYXJzOih2OnN0cmluZykgPT4gW3N0cmluZywgc3RyaW5nXSwgdHJpbVBhcmFtPzpzdHJpbmcpID0+IHtcbiAgICAgICAgY29uc3QgaW5wdXQgPSBlbC5xdWVyeVNlbGVjdG9yKFwiaW5wdXRcIikgYXMgSFRNTElucHV0RWxlbWVudDtcbiAgICAgICAgY29uc3QgbGluayA9IGVsLnF1ZXJ5U2VsZWN0b3IoXCJhXCIpIGFzIEhUTUxBbmNob3JFbGVtZW50O1xuICAgICAgICBjb25zdCBpbml0aWFsID0gaW5wdXQudmFsdWU7XG4gICAgICAgIGNvbnN0IGFjdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmIChpbnB1dC52YWx1ZSA9PT0gaW5pdGlhbCkgeyByZXR1cm4gfSAgLy8gbm90IGNoYW5nZWRcbiAgICAgICAgICAgIGNvbnN0IFttaW4sIHZhbCwgbWF4XSA9IFtpbnB1dC5taW4sIGlucHV0LnZhbHVlLCBpbnB1dC5tYXhdLm1hcChuID0+IHBhcnNlSW50KG4pIHx8IDApO1xuICAgICAgICAgICAgaWYgKHZhbCA8IG1pbiB8fCB2YWwgPiBtYXgpIHsgIC8vIHJlc2V0IGludmFsaWQvb3V0LW9mLXJhbmdlXG4gICAgICAgICAgICAgICAgaW5wdXQudmFsdWUgPSBpbml0aWFsO1xuICAgICAgICAgICAgICAgIGlucHV0LnNlbGVjdCgpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBbcGFnZSwgdXJsXSA9IGdldFZhcnMoaW5wdXQudmFsdWUpOyAgIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgcHJlZmVyLWNvbnN0XG4gICAgICAgICAgICBpZiAodHlwZW9mIHRyaW1QYXJhbSA9PT0gXCJzdHJpbmdcIiAmJiBwYWdlID09PSBcIjFcIikgeyB1cmwgPSB0cmltKHVybCwgdHJpbVBhcmFtKSB9XG4gICAgICAgICAgICBsaW5rLmhyZWYgPSB1cmw7XG4gICAgICAgICAgICBsaW5rLmNsaWNrKCk7XG4gICAgICAgIH07XG4gICAgICAgIFtcImNoYW5nZVwiLCBcImZvY3VzXCJdLmZvckVhY2goZSA9PiBpbnB1dC5hZGRFdmVudExpc3RlbmVyKGUsIGlucHV0LnNlbGVjdCkpOyAgICAgICAgLy8gYXV0by1zZWxlY3RcbiAgICAgICAgaW5wdXQuYWRkRXZlbnRMaXN0ZW5lcihcImZvY3Vzb3V0XCIsIGFjdGlvbik7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdHJpZ2dlciBhY3Rpb25cbiAgICAgICAgaW5wdXQuYWRkRXZlbnRMaXN0ZW5lcihcImtleXByZXNzXCIsIGUgPT4geyBpZiAoZS5rZXkgPT09IFwiRW50ZXJcIikgeyBhY3Rpb24oKSB9IH0pOyAvLyB0cmlnZ2VyIGFjdGlvblxuICAgIH07XG5cbiAgICAvLyBUcmltIHRoZSAke3BhZ2UtcGFyYW19PTEgcGFyYW1zIGluIGxpbmtzXG4gICAgY29uc3QgdHJpbSA9IChhOnN0cmluZywgcGFyYW06c3RyaW5nKSA9PlxuICAgICAgICBhLnJlcGxhY2UobmV3IFJlZ0V4cChgWz8mXSR7cGFyYW19PTFcXFxcYig/ISYpfFxcXFxiJHtwYXJhbX09MSZgKSwgXCJcIik7XG5cbiAgICAvLyBQdWJsaWMgaW50ZXJmYWNlXG4gICAgcmV0dXJuIHtcbiAgICAgICAgdmVyc2lvbjogXCI4LjAuMlwiLFxuXG4gICAgICAgIC8vIFNjYW4gZm9yIGVsZW1lbnRzIHdpdGggYSBcImRhdGEtcGFneVwiIGF0dHJpYnV0ZSBhbmQgY2FsbCB0aGVpciBpbml0IGZ1bmN0aW9ucyB3aXRoIHRoZSBkZWNvZGVkIGFyZ3NcbiAgICAgICAgaW5pdChhcmc/OkVsZW1lbnQgfCBuZXZlcikge1xuICAgICAgICAgICAgY29uc3QgdGFyZ2V0ID0gYXJnIGluc3RhbmNlb2YgRWxlbWVudCA/IGFyZyA6IGRvY3VtZW50O1xuICAgICAgICAgICAgY29uc3QgZWxlbWVudHMgPSB0YXJnZXQucXVlcnlTZWxlY3RvckFsbChcIltkYXRhLXBhZ3ldXCIpO1xuICAgICAgICAgICAgZm9yIChjb25zdCBlbCBvZiBlbGVtZW50cykge1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHVpbnQ4YXJyYXkgPSBVaW50OEFycmF5LmZyb20oYXRvYihlbC5nZXRBdHRyaWJ1dGUoXCJkYXRhLXBhZ3lcIikgYXMgc3RyaW5nKSwgYyA9PiBjLmNoYXJDb2RlQXQoMCkpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBba2V5d29yZCwgLi4uYXJnc10gPSBKU09OLnBhcnNlKChuZXcgVGV4dERlY29kZXIoKSkuZGVjb2RlKHVpbnQ4YXJyYXkpKTsgLy8gYmFzZTY0LXV0ZjggLT4gSlNPTiAtPiBBcnJheVxuICAgICAgICAgICAgICAgICAgICBpZiAoa2V5d29yZCA9PT0gXCJuYXZcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaW5pdE5hdihlbCBhcyBOYXZFbGVtZW50LCBhcmdzIGFzIE5hdkFyZ3MpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGtleXdvcmQgPT09IFwiY29tYm9cIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaW5pdENvbWJvKGVsLCBhcmdzIGFzIENvbWJvQXJncyk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoa2V5d29yZCA9PT0gXCJzZWxlY3RvclwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpbml0U2VsZWN0b3IoZWwsIGFyZ3MgYXMgU2VsZWN0b3JBcmdzKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcIlNraXBwZWQgUGFneS5pbml0KCkgZm9yOiAlb1xcblVua25vd24ga2V5d29yZCAnJXMnXCIsIGVsLCBrZXl3b3JkKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycikgeyBjb25zb2xlLndhcm4oXCJTa2lwcGVkIFBhZ3kuaW5pdCgpIGZvcjogJW9cXG4lc1wiLCBlbCwgZXJyKSB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xufSkoKTtcbiJdfQ== \ No newline at end of file +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFneS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInBhZ3kudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQWtCQSxNQUFNLElBQUksR0FBRyxDQUFDLEdBQUcsRUFBRTtJQUNmLDRDQUE0QztJQUM1QyxNQUFNLFdBQVcsR0FBRyxJQUFJLGNBQWMsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUNOLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFhLFdBQVcsQ0FBQyxDQUFDLE9BQU8sQ0FDM0UsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFeEUsNEJBQTRCO0lBQzVCLE1BQU0sT0FBTyxHQUFHLENBQUMsRUFBYSxFQUFFLENBQUMsTUFBTSxFQUFFLE9BQU8sRUFBRSxZQUFZLEVBQUUsU0FBUyxDQUFTLEVBQUUsRUFBRTtRQUNsRixNQUFNLFNBQVMsR0FBRyxFQUFFLENBQUMsYUFBYSxJQUFJLEVBQUUsQ0FBQztRQUN6QyxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNoRixJQUFJLFNBQVMsR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNuQixNQUFNLE1BQU0sR0FBRyxDQUFDLENBQVEsRUFBRSxJQUFXLEVBQUUsS0FBWSxFQUFTLEVBQUUsQ0FDMUQsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUMsaUJBQWlCLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDeEUsQ0FBQyxFQUFFLENB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TyxHQUFHLEVBQUUsQ0FBQztvQkFBQyxPQUFPLENBQUMsSUFBSSxDQUFDLGlDQUFpQyxFQUFFLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQTtnQkFBQyxDQUFDO1lBQzlFLENBQUM7UUFDTCxDQUFDO0tBQ0osQ0FBQztBQUNOLENBQUMsQ0FBQyxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJ0eXBlIE5hdkFyZ3MgPSByZWFkb25seSBbVG9rZW5zLCBTZXF1ZWxzLCBudWxsIHwgTGFiZWxTZXF1ZWxzLCBzdHJpbmc/XVxudHlwZSBDb21ib0FyZ3MgPSByZWFkb25seSBbc3RyaW5nLCBzdHJpbmc/XVxudHlwZSBTZWxlY3RvckFyZ3MgPSByZWFkb25seSBbbnVtYmVyLCBzdHJpbmcsIHN0cmluZz9dXG5cbmludGVyZmFjZSBUb2tlbnMge1xuICAgIHJlYWRvbmx5IGJlZm9yZTpzdHJpbmdcbiAgICByZWFkb25seSBhOnN0cmluZ1xuICAgIHJlYWRvbmx5IGN1cnJlbnQ6c3RyaW5nXG4gICAgcmVhZG9ubHkgZ2FwOnN0cmluZ1xuICAgIHJlYWRvbmx5IGFmdGVyOnN0cmluZ1xufVxuXG5pbnRlcmZhY2UgU2VxdWVscyB7cmVhZG9ubHkgW3dpZHRoOnN0cmluZ106KHN0cmluZyB8IG51bWJlcilbXX1cblxuaW50ZXJmYWNlIExhYmVsU2VxdWVscyB7cmVhZG9ubHkgW3dpZHRoOnN0cmluZ106c3RyaW5nW119XG5cbmludGVyZmFjZSBOYXZFbGVtZW50IGV4dGVuZHMgRWxlbWVudCB7cGFneVJlbmRlcigpOnZvaWR9XG5cbmNvbnN0IFBhZ3kgPSAoKCkgPT4ge1xuICAgIC8vIFRoZSBvYnNlcnZlciBpbnN0YW5jZSBmb3IgcmVzcG9uc2l2ZSBuYXZzXG4gICAgY29uc3QgcmpzT2JzZXJ2ZXIgPSBuZXcgUmVzaXplT2JzZXJ2ZXIoZW50cmllcyA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbnRyaWVzLmZvckVhY2goZSA9PiBlLnRhcmdldC5xdWVyeVNlbGVjdG9yQWxsPE5hdkVsZW1lbnQ+KFwiLnBhZ3ktcmpzXCIpLmZvckVhY2goXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbCA9PiBlbC5wYWd5UmVuZGVyKCkpKSk7XG5cbiAgICAvLyBJbml0IHRoZSAqX25hdl9qcyBoZWxwZXJzXG4gICAgY29uc3QgaW5pdE5hdiA9IChlbDpOYXZFbGVtZW50LCBbdG9rZW5zLCBzZXF1ZWxzLCBsYWJlbFNlcXVlbHMsIHRyaW1QYXJhbV06TmF2QXJncykgPT4ge1xuICAgICAgICBjb25zdCBjb250YWluZXIgPSBlbC5wYXJlbnRFbGVtZW50ID8/IGVsO1xuICAgICAgICBjb25zdCB3aWR0aHMgPSBPYmplY3Qua2V5cyhzZXF1ZWxzKS5tYXAodyA9PiBwYXJzZUludCh3KSkuc29ydCgoYSwgYikgPT4gYiAtIGEpO1xuICAgICAgICBsZXQgbGFzdFdpZHRoID0gLTE7XG4gICAgICAgIGNvbnN0IGZpbGxJbiA9IChhOnN0cmluZywgcGFnZTpzdHJpbmcsIGxhYmVsOnN0cmluZyk6c3RyaW5nID0+XG4gICAgICAgICAgICBhLnJlcGxhY2UoL19fcGFneV9wYWdlX18vZywgcGFnZSkucmVwbGFjZSgvX19wYWd5X2xhYmVsX18vZywgbGFiZWwpO1xuICAgICAgICAoZWwucGFneVJlbmRlciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGNvbnN0IHdpZHRoID0gd2lkdGhzLmZpbmQodyA9PiB3IDwgY29udGFpbmVyLmNsaWVudFdpZHRoKSB8fCAwO1xuICAgICAgICAgICAgaWYgKHdpZHRoID09PSBsYXN0V2lkdGgpIHsgcmV0dXJuIH0gLy8gbm8gY2hhbmdlOiBhYm9ydFxuICAgICAgICAgICAgbGV0IGh0bWwgPSB0b2tlbnMuYmVmb3JlOyAgLy8gYWxyZWFkeSB0cmltbWVkIGluIGh0bWxcbiAgICAgICAgICAgIGNvbnN0IHNlcmllcyA9IHNlcXVlbHNbd2lkdGgudG9TdHJpbmcoKV07XG4gICAgICAgICAgICBjb25zdCBsYWJlbHMgPSBsYWJlbFNlcXVlbHM/Llt3aWR0aC50b1N0cmluZygpXSA/PyBzZXJpZXMubWFwKGwgPT4gbC50b1N0cmluZygpKTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgaSBpbiBzZXJpZXMpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBpdGVtID0gc2VyaWVzW2ldO1xuICAgICAgICAgICAgICAgIGNvbnN0IGxhYmVsID0gbGFiZWxzW2ldO1xuICAgICAgICAgICAgICAgIGxldCBmaWxsZWQ7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBpdGVtID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGZpbGxlZCA9IGZpbGxJbih0b2tlbnMuYSwgaXRlbS50b1N0cmluZygpLCBsYWJlbCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChpdGVtID09PSBcImdhcFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGZpbGxlZCA9IHRva2Vucy5nYXA7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHsgLy8gYWN0aXZlIHBhZ2VcbiAgICAgICAgICAgICAgICAgICAgZmlsbGVkID0gZmlsbEluKHRva2Vucy5jdXJyZW50LCBpdGVtLCBsYWJlbCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGh0bWwgKz0gKHR5cGVvZiB0cmltUGFyYW0gPT09IFwic3RyaW5nXCIgJiYgaXRlbSA9PSAxKSA/IHRyaW0oZmlsbGVkLCB0cmltUGFyYW0pIDogZmlsbGVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaHRtbCArPSB0b2tlbnMuYWZ0ZXI7ICAgLy8gZXNsaW50LWRpc2FibGUtbGluZSBhbGlnbi1hc3NpZ25tZW50cy9hbGlnbi1hc3NpZ25tZW50c1xuICAgICAgICAgICAgZWwuaW5uZXJIVE1MID0gXCJcIjtcbiAgICAgICAgICAgIGVsLmluc2VydEFkamFjZW50SFRNTChcImFmdGVyYmVnaW5cIiwgaHRtbCk7XG4gICAgICAgICAgICBsYXN0V2lkdGggPSB3aWR0aDtcbiAgICAgICAgfSkoKTtcbiAgICAgICAgaWYgKGVsLmNsYXNzTGlzdC5jb250YWlucyhcInBhZ3ktcmpzXCIpKSB7IHJqc09ic2VydmVyLm9ic2VydmUoY29udGFpbmVyKSB9XG4gICAgfTtcblxuICAgIC8vIEluaXQgdGhlICpfY29tYm9fbmF2X2pzIGhlbHBlcnNcbiAgICBjb25zdCBpbml0Q29tYm8gPSAoZWw6RWxlbWVudCwgW3VybF90b2tlbiwgdHJpbVBhcmFtXTpDb21ib0FyZ3MpID0+XG4gICAgICAgIGluaXRJbnB1dChlbCwgaW5wdXRWYWx1ZSA9PiBbaW5wdXRWYWx1ZSwgdXJsX3Rva2VuLnJlcGxhY2UoL19fcGFneV9wYWdlX18vLCBpbnB1dFZhbHVlKV0sIHRyaW1QYXJhbSk7XG5cbiAgICAvLyBJbml0IHRoZSBpdGVtc19zZWxlY3Rvcl9qcyBoZWxwZXJcbiAgICBjb25zdCBpbml0U2VsZWN0b3IgPSAoZWw6RWxlbWVudCwgW2Zyb20sIHVybF90b2tlbiwgdHJpbVBhcmFtXTpTZWxlY3RvckFyZ3MpID0+IHtcbiAgICAgICAgaW5pdElucHV0KGVsLCBpbnB1dFZhbHVlID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHBhZ2UgPSBNYXRoLm1heChNYXRoLmNlaWwoZnJvbSAvIHBhcnNlSW50KGlucHV0VmFsdWUpKSwgMSkudG9TdHJpbmcoKTtcbiAgICAgICAgICAgIGNvbnN0IHVybCA9IHVybF90b2tlbi5yZXBsYWNlKC9fX3BhZ3lfcGFnZV9fLywgcGFnZSkucmVwbGFjZSgvX19wYWd5X2l0ZW1zX18vLCBpbnB1dFZhbHVlKTtcbiAgICAgICAgICAgIHJldHVybiBbcGFnZSwgdXJsXTtcbiAgICAgICAgfSwgdHJpbVBhcmFtKTtcbiAgICB9O1xuXG4gICAgLy8gSW5pdCB0aGUgaW5wdXQgZWxlbWVudFxuICAgIGNvbnN0IGluaXRJbnB1dCA9IChlbDpFbGVtZW50LCBnZXRWYXJzOih2OnN0cmluZykgPT4gW3N0cmluZywgc3RyaW5nXSwgdHJpbVBhcmFtPzpzdHJpbmcpID0+IHtcbiAgICAgICAgY29uc3QgaW5wdXQgPSBlbC5xdWVyeVNlbGVjdG9yKFwiaW5wdXRcIikgYXMgSFRNTElucHV0RWxlbWVudDtcbiAgICAgICAgY29uc3QgbGluayA9IGVsLnF1ZXJ5U2VsZWN0b3IoXCJhXCIpIGFzIEhUTUxBbmNob3JFbGVtZW50O1xuICAgICAgICBjb25zdCBpbml0aWFsID0gaW5wdXQudmFsdWU7XG4gICAgICAgIGNvbnN0IGFjdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmIChpbnB1dC52YWx1ZSA9PT0gaW5pdGlhbCkgeyByZXR1cm4gfSAgLy8gbm90IGNoYW5nZWRcbiAgICAgICAgICAgIGNvbnN0IFttaW4sIHZhbCwgbWF4XSA9IFtpbnB1dC5taW4sIGlucHV0LnZhbHVlLCBpbnB1dC5tYXhdLm1hcChuID0+IHBhcnNlSW50KG4pIHx8IDApO1xuICAgICAgICAgICAgaWYgKHZhbCA8IG1pbiB8fCB2YWwgPiBtYXgpIHsgIC8vIHJlc2V0IGludmFsaWQvb3V0LW9mLXJhbmdlXG4gICAgICAgICAgICAgICAgaW5wdXQudmFsdWUgPSBpbml0aWFsO1xuICAgICAgICAgICAgICAgIGlucHV0LnNlbGVjdCgpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBbcGFnZSwgdXJsXSA9IGdldFZhcnMoaW5wdXQudmFsdWUpOyAgIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgcHJlZmVyLWNvbnN0XG4gICAgICAgICAgICBpZiAodHlwZW9mIHRyaW1QYXJhbSA9PT0gXCJzdHJpbmdcIiAmJiBwYWdlID09PSBcIjFcIikgeyB1cmwgPSB0cmltKHVybCwgdHJpbVBhcmFtKSB9XG4gICAgICAgICAgICBsaW5rLmhyZWYgPSB1cmw7XG4gICAgICAgICAgICBsaW5rLmNsaWNrKCk7XG4gICAgICAgIH07XG4gICAgICAgIFtcImNoYW5nZVwiLCBcImZvY3VzXCJdLmZvckVhY2goZSA9PiBpbnB1dC5hZGRFdmVudExpc3RlbmVyKGUsIGlucHV0LnNlbGVjdCkpOyAgICAgICAgLy8gYXV0by1zZWxlY3RcbiAgICAgICAgaW5wdXQuYWRkRXZlbnRMaXN0ZW5lcihcImZvY3Vzb3V0XCIsIGFjdGlvbik7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdHJpZ2dlciBhY3Rpb25cbiAgICAgICAgaW5wdXQuYWRkRXZlbnRMaXN0ZW5lcihcImtleXByZXNzXCIsIGUgPT4geyBpZiAoZS5rZXkgPT09IFwiRW50ZXJcIikgeyBhY3Rpb24oKSB9IH0pOyAvLyB0cmlnZ2VyIGFjdGlvblxuICAgIH07XG5cbiAgICAvLyBUcmltIHRoZSAke3BhZ2UtcGFyYW19PTEgcGFyYW1zIGluIGxpbmtzXG4gICAgY29uc3QgdHJpbSA9IChhOnN0cmluZywgcGFyYW06c3RyaW5nKSA9PlxuICAgICAgICBhLnJlcGxhY2UobmV3IFJlZ0V4cChgWz8mXSR7cGFyYW19PTFcXFxcYig/ISYpfFxcXFxiJHtwYXJhbX09MSZgKSwgXCJcIik7XG5cbiAgICAvLyBQdWJsaWMgaW50ZXJmYWNlXG4gICAgcmV0dXJuIHtcbiAgICAgICAgdmVyc2lvbjogXCI4LjEuMFwiLFxuXG4gICAgICAgIC8vIFNjYW4gZm9yIGVsZW1lbnRzIHdpdGggYSBcImRhdGEtcGFneVwiIGF0dHJpYnV0ZSBhbmQgY2FsbCB0aGVpciBpbml0IGZ1bmN0aW9ucyB3aXRoIHRoZSBkZWNvZGVkIGFyZ3NcbiAgICAgICAgaW5pdChhcmc/OkVsZW1lbnQgfCBuZXZlcikge1xuICAgICAgICAgICAgY29uc3QgdGFyZ2V0ID0gYXJnIGluc3RhbmNlb2YgRWxlbWVudCA/IGFyZyA6IGRvY3VtZW50O1xuICAgICAgICAgICAgY29uc3QgZWxlbWVudHMgPSB0YXJnZXQucXVlcnlTZWxlY3RvckFsbChcIltkYXRhLXBhZ3ldXCIpO1xuICAgICAgICAgICAgZm9yIChjb25zdCBlbCBvZiBlbGVtZW50cykge1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHVpbnQ4YXJyYXkgPSBVaW50OEFycmF5LmZyb20oYXRvYihlbC5nZXRBdHRyaWJ1dGUoXCJkYXRhLXBhZ3lcIikgYXMgc3RyaW5nKSwgYyA9PiBjLmNoYXJDb2RlQXQoMCkpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBba2V5d29yZCwgLi4uYXJnc10gPSBKU09OLnBhcnNlKChuZXcgVGV4dERlY29kZXIoKSkuZGVjb2RlKHVpbnQ4YXJyYXkpKTsgLy8gYmFzZTY0LXV0ZjggLT4gSlNPTiAtPiBBcnJheVxuICAgICAgICAgICAgICAgICAgICBpZiAoa2V5d29yZCA9PT0gXCJuYXZcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaW5pdE5hdihlbCBhcyBOYXZFbGVtZW50LCBhcmdzIGFzIE5hdkFyZ3MpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGtleXdvcmQgPT09IFwiY29tYm9cIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaW5pdENvbWJvKGVsLCBhcmdzIGFzIENvbWJvQXJncyk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoa2V5d29yZCA9PT0gXCJzZWxlY3RvclwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpbml0U2VsZWN0b3IoZWwsIGFyZ3MgYXMgU2VsZWN0b3JBcmdzKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcIlNraXBwZWQgUGFneS5pbml0KCkgZm9yOiAlb1xcblVua25vd24ga2V5d29yZCAnJXMnXCIsIGVsLCBrZXl3b3JkKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGVycikgeyBjb25zb2xlLndhcm4oXCJTa2lwcGVkIFBhZ3kuaW5pdCgpIGZvcjogJW9cXG4lc1wiLCBlbCwgZXJyKSB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xufSkoKTtcbiJdfQ== \ No newline at end of file diff --git a/gem/javascripts/pagy-module.js b/gem/javascripts/pagy-module.js index 8e6e3b939..3b70e96e8 100644 --- a/gem/javascripts/pagy-module.js +++ b/gem/javascripts/pagy-module.js @@ -81,7 +81,7 @@ const Pagy = (() => { const trim = (a, param) => a.replace(new RegExp(`[?&]${param}=1\\b(?!&)|\\b${param}=1&`), ""); // Public interface return { - version: "8.0.2", + version: "8.1.0", // Scan for elements with a "data-pagy" attribute and call their init functions with the decoded args init(arg) { const target = arg instanceof Element ? arg : document; diff --git a/gem/javascripts/pagy.js b/gem/javascripts/pagy.js index 082a02238..059c1ccb1 100644 --- a/gem/javascripts/pagy.js +++ b/gem/javascripts/pagy.js @@ -1 +1 @@ -!function(){let e=(()=>{let e=new ResizeObserver(e=>e.forEach(e=>e.target.querySelectorAll(".pagy-rjs").forEach(e=>e.pagyRender()))),t=(t,[r,a,n,l])=>{let i=t.parentElement??t,c=Object.keys(a).map(e=>parseInt(e)).sort((e,t)=>t-e),p=-1,s=(e,t,r)=>e.replace(/__pagy_page__/g,t).replace(/__pagy_label__/g,r);(t.pagyRender=function(){let e=c.find(e=>ee.toString());for(let e in y){let t;let a=y[e],n=f[e];t="number"==typeof a?s(r.a,a.toString(),n):"gap"===a?r.gap:s(r.current,a,n),g+="string"==typeof l&&1==a?o(t,l):t}g+=r.after,t.innerHTML="",t.insertAdjacentHTML("afterbegin",g),p=e})(),t.classList.contains("pagy-rjs")&&e.observe(i)},r=(e,[t,r])=>n(e,e=>[e,t.replace(/__pagy_page__/,e)],r),a=(e,[t,r,a])=>{n(e,e=>{let a=Math.max(Math.ceil(t/parseInt(e)),1).toString(),n=r.replace(/__pagy_page__/,a).replace(/__pagy_items__/,e);return[a,n]},a)},n=(e,t,r)=>{let a=e.querySelector("input"),n=e.querySelector("a"),l=a.value,i=function(){if(a.value===l)return;let[e,i,c]=[a.min,a.value,a.max].map(e=>parseInt(e)||0);if(ic){a.value=l,a.select();return}let[p,s]=t(a.value);"string"==typeof r&&"1"===p&&(s=o(s,r)),n.href=s,n.click()};["change","focus"].forEach(e=>a.addEventListener(e,a.select)),a.addEventListener("focusout",i),a.addEventListener("keypress",e=>{"Enter"===e.key&&i()})},o=(e,t)=>e.replace(RegExp(`[?&]${t}=1\\b(?!&)|\\b${t}=1&`),"");return{version:"8.0.2",init(e){for(let n of(e instanceof Element?e:document).querySelectorAll("[data-pagy]"))try{let e=Uint8Array.from(atob(n.getAttribute("data-pagy")),e=>e.charCodeAt(0)),[o,...l]=JSON.parse(new TextDecoder().decode(e));"nav"===o?t(n,l):"combo"===o?r(n,l):"selector"===o?a(n,l):console.warn("Skipped Pagy.init() for: %o\nUnknown keyword '%s'",n,o)}catch(e){console.warn("Skipped Pagy.init() for: %o\n%s",n,e)}}}})();window.Pagy=e}(); \ No newline at end of file +!function(){let e=(()=>{let e=new ResizeObserver(e=>e.forEach(e=>e.target.querySelectorAll(".pagy-rjs").forEach(e=>e.pagyRender()))),t=(t,[r,a,n,l])=>{let i=t.parentElement??t,c=Object.keys(a).map(e=>parseInt(e)).sort((e,t)=>t-e),p=-1,s=(e,t,r)=>e.replace(/__pagy_page__/g,t).replace(/__pagy_label__/g,r);(t.pagyRender=function(){let e=c.find(e=>ee.toString());for(let e in y){let t;let a=y[e],n=f[e];t="number"==typeof a?s(r.a,a.toString(),n):"gap"===a?r.gap:s(r.current,a,n),g+="string"==typeof l&&1==a?o(t,l):t}g+=r.after,t.innerHTML="",t.insertAdjacentHTML("afterbegin",g),p=e})(),t.classList.contains("pagy-rjs")&&e.observe(i)},r=(e,[t,r])=>n(e,e=>[e,t.replace(/__pagy_page__/,e)],r),a=(e,[t,r,a])=>{n(e,e=>{let a=Math.max(Math.ceil(t/parseInt(e)),1).toString(),n=r.replace(/__pagy_page__/,a).replace(/__pagy_items__/,e);return[a,n]},a)},n=(e,t,r)=>{let a=e.querySelector("input"),n=e.querySelector("a"),l=a.value,i=function(){if(a.value===l)return;let[e,i,c]=[a.min,a.value,a.max].map(e=>parseInt(e)||0);if(ic){a.value=l,a.select();return}let[p,s]=t(a.value);"string"==typeof r&&"1"===p&&(s=o(s,r)),n.href=s,n.click()};["change","focus"].forEach(e=>a.addEventListener(e,a.select)),a.addEventListener("focusout",i),a.addEventListener("keypress",e=>{"Enter"===e.key&&i()})},o=(e,t)=>e.replace(RegExp(`[?&]${t}=1\\b(?!&)|\\b${t}=1&`),"");return{version:"8.1.0",init(e){for(let n of(e instanceof Element?e:document).querySelectorAll("[data-pagy]"))try{let e=Uint8Array.from(atob(n.getAttribute("data-pagy")),e=>e.charCodeAt(0)),[o,...l]=JSON.parse(new TextDecoder().decode(e));"nav"===o?t(n,l):"combo"===o?r(n,l):"selector"===o?a(n,l):console.warn("Skipped Pagy.init() for: %o\nUnknown keyword '%s'",n,o)}catch(e){console.warn("Skipped Pagy.init() for: %o\n%s",n,e)}}}})();window.Pagy=e}(); \ No newline at end of file diff --git a/gem/lib/pagy.rb b/gem/lib/pagy.rb index bd4b008ef..b31f731e1 100644 --- a/gem/lib/pagy.rb +++ b/gem/lib/pagy.rb @@ -5,7 +5,7 @@ # Core class class Pagy - VERSION = '8.0.2' + VERSION = '8.1.0' # Gem root pathname to get the path of Pagy files stylesheets, javascripts, apps, locales, etc. def self.root diff --git a/quick-start.md b/quick-start.md index 84ebda5a6..ef2d4add9 100644 --- a/quick-start.md +++ b/quick-start.md @@ -40,7 +40,7 @@ If you use Bundler, add the gem in the Gemfile, optionally avoiding the next maj see [RubyGem Specifiers](http://guides.rubygems.org/patterns/#pessimistic-version-constraint)): ```ruby Gemfile -gem 'pagy', '~> 8.0' # omit patch digit +gem 'pagy', '~> 8.1' # omit patch digit ``` +++ Without Bundler diff --git a/retype.yml b/retype.yml index a48ed2fd0..e03b937b7 100644 --- a/retype.yml +++ b/retype.yml @@ -8,7 +8,7 @@ url: https://ddnexus.github.io/pagy branding: title: Pagy - label: 8.0.2 + label: 8.1.0 colors: label: text: "#FFFFFF" diff --git a/src/pagy.ts b/src/pagy.ts index 5db65732d..a4d6dcd7b 100644 --- a/src/pagy.ts +++ b/src/pagy.ts @@ -98,7 +98,7 @@ const Pagy = (() => { // Public interface return { - version: "8.0.2", + version: "8.1.0", // Scan for elements with a "data-pagy" attribute and call their init functions with the decoded args init(arg?:Element | never) {