Skip to content

Commit

Permalink
simplified the items extra, and added its features to the array and a…
Browse files Browse the repository at this point in the history
…rel extras
  • Loading branch information
ddnexus committed Apr 28, 2021
1 parent 86fb20e commit 76096e7
Show file tree
Hide file tree
Showing 15 changed files with 197 additions and 384 deletions.
44 changes: 25 additions & 19 deletions docs/extras/items.md
Expand Up @@ -3,7 +3,7 @@ title: Items
---
# Items Extra

Allow the client to request a custom number of items per page with an optional selector UI. It is useful with APIs or higly user-customizable apps.
Allow the client to request a custom number of items per page with an optional selector UI. It is useful with APIs or user-customizable UIs.

It works also with the [countless](countless.md), [searchkick](searchkick.md) and [elasticsearch_rails](elasticsearch_rails.md) extras.

Expand All @@ -16,8 +16,21 @@ In the `pagy.rb` initializer:
```ruby
require 'pagy/extras/items'

# it will work without any further configuration

# you can disable it explicitly for specific requests
@pagy, @records = pagy(Product.all, enable_items_extra: false)

# or...

# disable it by default (opt-in)
Pagy::VARS[:enable_items_extra] = false # default true
# in this case you have to enable it explicitly when you want it
@pagy, @records = pagy(Product.all, enable_items_extra: true)

# customize the defaults if you need to
Pagy::VARS[:items_param] = :custom_param # default :items
Pagy::VARS[:max_items] = 100 # default
Pagy::VARS[:max_items] = 200 # default 100
```

See [Javascript](../api/javascript.md) (only if you use the `pagy_items_selector_js` UI)
Expand All @@ -28,10 +41,13 @@ See [Javascript](../api/javascript.md) (only if you use the `pagy_items_selector

## Variables

| Variable | Description | Default |
|:---------------|:---------------------------------------------------------------------|:---------|
| `:items_param` | the name of the items param used in the url. | `:items` |
| `:max_items` | the max items allowed to be requested. Set it to `nil` for no limit. | `100` |
| Variable | Description | Default |
|:----------------------|:---------------------------------------------------------------------|:---------|
| `:enable_items_extra` | enable or disable the feature | `true` |
| `:items_param` | the name of the items param used in the url. | `:items` |
| `:max_items` | the max items allowed to be requested. Set it to `nil` for no limit. | `100` |

You can use the `:enable_items_extra` variable to opt-out of the feature even when the extra is required.

This extra uses the `:items_param` variable to determine the param it should get the number of `:items` from.

Expand Down Expand Up @@ -63,26 +79,16 @@ pagy(scope, items: 30)

## Methods

The `items` extra overrides a couple of builtin methods and adds a helper to the `Pagy::Frontend` module.

### pagy_get_vars(collection, vars)

This extra overrides the `pagy_get_vars` method of the `Pagy::Backend` module in order to set the `:items` variable, pulled from the request-params.

### pagy_countless_get_vars(collection, vars)

This extra overrides the `pagy_countless_get_vars` method of the `Pagy::Backend` module (added by the `countless` extra) in order to set the `:items` variable, pulled from the request-params.

### pagy_url_for(pagy, page, absolute: nil)

This extra overrides also the `pagy_url_for` method of the `Pagy::Frontend` module in order to add the `:items_param` param to the url of the links.
The `items` extra adds the `pagy_items_selector_js` helper to the `Pagy::Frontend` module.

### pagy_items_selector_js(pagy, ...)

This helper provides an items selector UI, which allows the user to select any arbitrary number of items per page (below the `:max_items` number) in a numeric input field. It looks like:

<span>Show <input type="number" min="1" max="100" value="20" style="padding: 0; text-align: center; width: 3rem;"> items per page</span>

It returns an empty string if the `:enable_items_extra` is `false`.

The method accepts also a few optional keyword arguments:
- `:pagy_id` which adds the `id` HTML attributedto the `nav` tag
- `:item_name` an already pluralized string that will be used in place of the default `item/items`
Expand Down
2 changes: 2 additions & 0 deletions lib/config/pagy.rb
Expand Up @@ -87,6 +87,8 @@
# require 'pagy/extras/items'
# Pagy::VARS[:items_param] = :items # default
# Pagy::VARS[:max_items] = 100 # default
# set to false if you want to make :enable_items_extra an opt-in variable
# Pagy::VARS[:enable_items_extra] = false # default true

# Overflow extra: Allow for easy handling of overflowing pages
# See https://ddnexus.github.io/pagy/extras/overflow
Expand Down
1 change: 1 addition & 0 deletions lib/pagy/backend.rb
Expand Up @@ -19,6 +19,7 @@ def pagy(collection, vars={})

# Sub-method called only by #pagy: here for easy customization of variables by overriding
def pagy_get_vars(collection, vars)
pagy_set_items_from_params(vars) if defined?(UseItemsExtra)
vars[:count] ||= (c = collection.count(:all)).is_a?(Hash) ? c.size : c
vars[:page] ||= params[ vars[:page_param] || VARS[:page_param] ]
vars
Expand Down
1 change: 1 addition & 0 deletions lib/pagy/extras/arel.rb
Expand Up @@ -11,6 +11,7 @@ def pagy_arel(collection, vars={})
end

def pagy_arel_get_vars(collection, vars)
pagy_set_items_from_params(vars) if defined?(UseItemsExtra)
vars[:count] ||= pagy_arel_count(collection)
vars[:page] ||= params[ vars[:page_param] || VARS[:page_param] ]
vars
Expand Down
1 change: 1 addition & 0 deletions lib/pagy/extras/array.rb
Expand Up @@ -14,6 +14,7 @@ def pagy_array(array, vars={})

# Sub-method called only by #pagy_array: here for easy customization of variables by overriding
def pagy_array_get_vars(array, vars)
pagy_set_items_from_params(vars) if defined?(UseItemsExtra)
vars[:count] ||= array.size
vars[:page] ||= params[ vars[:page_param] || VARS[:page_param] ]
vars
Expand Down
3 changes: 2 additions & 1 deletion lib/pagy/extras/countless.rb
Expand Up @@ -16,7 +16,8 @@ def pagy_countless(collection, vars={})

# Sub-method called only by #pagy_countless: here for easy customization of variables by overriding
def pagy_countless_get_vars(_collection, vars)
vars[:page] ||= params[ vars[:page_param] || VARS[:page_param] ]
pagy_set_items_from_params(vars) if defined?(UseItemsExtra)
vars[:page] ||= params[ vars[:page_param] || VARS[:page_param] ]
vars
end

Expand Down
1 change: 1 addition & 0 deletions lib/pagy/extras/elasticsearch_rails.rb
Expand Up @@ -51,6 +51,7 @@ def pagy_elasticsearch_rails(pagy_search_args, vars={})
# Sub-method called only by #pagy_elasticsearch_rails: here for easy customization of variables by overriding
# the _collection argument is not available when the method is called
def pagy_elasticsearch_rails_get_vars(_collection, vars)
pagy_set_items_from_params(vars) if defined?(UseItemsExtra)
vars[:items] ||= VARS[:items]
vars[:page] ||= (params[ vars[:page_param] || VARS[:page_param] ] || 1).to_i
vars
Expand Down
43 changes: 11 additions & 32 deletions lib/pagy/extras/items.rb
Expand Up @@ -9,50 +9,29 @@ class Pagy
VARS[:items_param] = :items
VARS[:max_items] = 100

VARS[:enable_items_extra] = true

ITEMS_PLACEHOLDER = '__pagy_items__'

module UseItemsExtra
private
module UseItemsExtra; end

%i[ pagy_get_vars
pagy_countless_get_vars
pagy_elasticsearch_rails_get_vars
pagy_searchkick_get_vars
].each do |meth|
next unless Backend.private_method_defined?(meth, true)
module Backend
private

define_method(meth) do |collection, vars|
vars[:items] ||= if (items = params[vars[:items_param] || VARS[:items_param]]) # :items from :items_param
[items.to_i, vars.key?(:max_items) ? vars[:max_items] : VARS[:max_items]].compact.min # :items capped to :max_items
end
super collection, vars
def pagy_set_items_from_params(vars)
return if vars[:items]
return unless vars.key?(:enable_item_extra) ? vars[:enable_item_extra] : VARS[:enable_items_extra]
return unless (items = params[vars[:items_param] || VARS[:items_param]]) # :items from :items_param
vars[:items] = [items.to_i, vars.key?(:max_items) ? vars[:max_items] : VARS[:max_items]].compact.min # :items capped to :max_items
end
end

end
Backend.prepend UseItemsExtra


module Frontend

module UseItemsExtra

def pagy_url_for(pagy, page, deprecated_url=nil, absolute: nil)
absolute = Pagy.deprecated_arg(:url, deprecated_url, :absolute, absolute) if deprecated_url
pagy, page = Pagy.deprecated_order(pagy, page) if page.is_a?(Pagy)
p_vars = pagy.vars
params = request.GET.merge(p_vars[:params])
params[p_vars[:page_param].to_s] = page
params[p_vars[:items_param].to_s] = p_vars[:items]
query_string = "?#{Rack::Utils.build_nested_query(pagy_get_params(params))}" unless params.empty?
"#{request.base_url if absolute}#{request.path}#{query_string}#{p_vars[:anchor]}"
end

end
prepend UseItemsExtra

# Return the items selector HTML. For example "Show [20] items per page"
def pagy_items_selector_js(pagy, deprecated_id=nil, pagy_id: nil, item_name: nil, i18n_key: nil, link_extra: '')
return '' unless pagy.vars[:enable_items_extra]
pagy_id = Pagy.deprecated_arg(:id, deprecated_id, :pagy_id, pagy_id) if deprecated_id
p_id = %( id="#{pagy_id}") if pagy_id
p_vars = pagy.vars
Expand Down
1 change: 1 addition & 0 deletions lib/pagy/extras/searchkick.rb
Expand Up @@ -49,6 +49,7 @@ def pagy_searchkick(pagy_search_args, vars={})
# Sub-method called only by #pagy_searchkick: here for easy customization of variables by overriding
# the _collection argument is not available when the method is called
def pagy_searchkick_get_vars(_collection, vars)
pagy_set_items_from_params(vars) if defined?(UseItemsExtra)
vars[:items] ||= VARS[:items]
vars[:page] ||= (params[ vars[:page_param] || VARS[:page_param] ] || 1).to_i
vars
Expand Down
3 changes: 2 additions & 1 deletion lib/pagy/frontend.rb
Expand Up @@ -18,7 +18,8 @@ def pagy_url_for(pagy, page, deprecated_url=nil, absolute: nil)
pagy, page = Pagy.deprecated_order(pagy, page) if page.is_a?(Pagy)
p_vars = pagy.vars
params = request.GET.merge(p_vars[:params])
params[p_vars[:page_param].to_s] = page
params[p_vars[:page_param].to_s] = page
params[p_vars[:items_param].to_s] = p_vars[:items] if defined?(UseItemsExtra)
query_string = "?#{Rack::Utils.build_nested_query(pagy_get_params(params))}" unless params.empty?
"#{request.base_url if absolute}#{request.path}#{query_string}#{p_vars[:anchor]}"
end
Expand Down
3 changes: 1 addition & 2 deletions tasks/test.rake
Expand Up @@ -14,8 +14,7 @@ test_tasks = {}
shared_json
trim
items_trim
items_countless
items_elasticsearch
items
elasticsearch_rails
searchkick
].each do |name|
Expand Down
164 changes: 0 additions & 164 deletions test/pagy/extras/items_countless_test.rb

This file was deleted.

0 comments on commit 76096e7

Please sign in to comment.