-
Notifications
You must be signed in to change notification settings - Fork 408
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
384 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
--- | ||
title: Items | ||
--- | ||
# Items Extra | ||
|
||
Allow the client to request a custom number of items per page with a ready to use UI selector. It is useful with APIs or higly user-customizable apps. | ||
|
||
## Synopsys | ||
|
||
See [extras](../extras.md) for general usage info. | ||
|
||
In the Pagy initializer: | ||
|
||
```ruby | ||
require 'pagy/extra/items' | ||
|
||
Pagy::VARS[:items_param] = :custom_param # default :items | ||
Pagy::VARS[:max_items] = 100 # default | ||
|
||
# in rails apps: add the assets-path (only required if you use the pagy_items_selector helper) | ||
Rails.application.config.assets.paths << Pagy.root.join('pagy', 'extras', 'javascripts') | ||
``` | ||
|
||
In rails: add the javascript file to the application.js | ||
|
||
```js | ||
// only required if you use the pagy_items_selector helper | ||
//= require pagy-items | ||
``` | ||
|
||
In non-rails apps: ensure the `pagy/extras/javascripts/pagy-items.js` script gets served with the page. | ||
|
||
Then you may want to use the `pagy_items_selector` helper in any view: | ||
|
||
```erb | ||
<%== pagy_items_selector(@pagy) %> | ||
``` | ||
|
||
## Files | ||
|
||
This extra is composed of 2 small files: | ||
|
||
- [items.rb](https://github.com/ddnexus/pagy/blob/master/lib/pagy/extras/items.rb) | ||
- [pagy-items.js](https://github.com/ddnexus/pagy/blob/master/lib/pagy/extras/javascripts/pagy-items.js) | ||
|
||
## 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` | | ||
|
||
This extra uses the `:items_param` variable to determine the param it should get the number of `:items` from. | ||
|
||
The `:max_items` is used to cap the number of items to that max. It is set to `100` by default. If you don't want to limit the max requested number of items per page, you can set it to `nil`. | ||
|
||
You may want to customize the variables. Depending on the scope of the customization, you have a couple of options: | ||
|
||
As a global default: | ||
|
||
```ruby | ||
Pagy::VARS[:items_param] = :custom_param | ||
Pagy::VARS[:max_items] = 50 | ||
``` | ||
|
||
For a single instance (overriding the global default): | ||
|
||
```ruby | ||
pagy(scope, items_param: :custom_param, max_items: 50) | ||
Pagy.new(count:100, items_param: :custom_param, max_items: 50) | ||
``` | ||
|
||
**Notice**: you can override items that the client send with the params by passing the `:items` explicitly. For example: | ||
|
||
```ruby | ||
# this will ignore the params[:item] (or any custom :param_name) | ||
# from the client for this instance, and serve 30 items | ||
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. The built-in `pagy_get_vars` method is aliased as `built_in_pagy_get_vars` and is called internally and still available. | ||
|
||
### pagy_url_for(page, pagy) | ||
|
||
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. | ||
|
||
### pagy_items_selector(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> | ||
|
||
When the items number is changed with the selector, pagy will reload the pagination UI using the selected items per page. It will also request the _right_ page number calculated in order to contain the first item of the previously displayed page. That way the new displayed page will roughly show the same items in the collection. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
# See the Pagy documentation: https://ddnexus.github.io/pagy/extras/items | ||
|
||
class Pagy | ||
|
||
# Default variables for this extra | ||
VARS[:items_param] = :items | ||
VARS[:max_items] = 100 | ||
|
||
# Handle a custom number of :items from params | ||
module Backend ; private | ||
|
||
alias_method :built_in_pagy_get_vars, :pagy_get_vars | ||
|
||
def pagy_get_vars(collection, vars) | ||
vars[:items] ||= (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 | ||
built_in_pagy_get_vars(collection, vars) | ||
end | ||
|
||
end | ||
|
||
module Frontend | ||
|
||
# this works with all Rack-based frameworks (Sinatra, Padrino, Rails, ...) | ||
def pagy_url_for(page, pagy) | ||
p_vars = pagy.vars; params = request.GET.merge(p_vars[:page_param] => page, p_vars[:items_param] => p_vars[:items], **p_vars[:params]) | ||
"#{request.path}?#{Rack::Utils.build_nested_query(pagy_get_params(params))}#{p_vars[:anchor]}" | ||
end | ||
|
||
# return the items selector HTML. For example "Show [20] items per page" | ||
def pagy_items_selector(pagy, id=caller(1,1)[0].hash) | ||
pagy = pagy.clone; p_vars = pagy.vars; p_items = p_vars[:items]; p_vars[:items] = "#{MARKER}-items-" | ||
|
||
tags = %(<span id="pagy-items-#{id}">) | ||
|
||
tags << %(<a href="#{pagy_url_for("#{MARKER}-page-", pagy)}"></a>) | ||
input = %(<input type="number" min="1" max="#{p_vars[:max_items]}" value="#{p_items}" style="padding: 0; text-align: center; width: #{p_items.to_s.length+1}rem;">) | ||
tags << %(#{pagy_t('pagy.items.show'.freeze)} #{input} #{pagy_t('pagy.items.items'.freeze)}) | ||
|
||
tags << %(</span><script>PagyItems('#{id}', '#{MARKER}', #{pagy.from});</script>) | ||
end | ||
|
||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// See the Pagy documentation: https://ddnexus.github.io/pagy/extras/items | ||
|
||
function PagyItems(id, marker, from){ | ||
var pagyNav = document.getElementById('pagy-items-'+id), | ||
input = pagyNav.getElementsByTagName('input')[0], | ||
current = input.value, | ||
link = pagyNav.getElementsByTagName('a')[0]; | ||
|
||
this.go = function(){ | ||
var items = input.value; | ||
if (current !== items) { | ||
var page = Math.max(Math.ceil(from / items),1); | ||
var href = link.getAttribute('href').replace(marker+'-page-', page).replace(marker+'-items-', items); | ||
link.setAttribute('href', href); | ||
link.click(); | ||
} | ||
}; | ||
|
||
// select the content on click: easier for typing a number | ||
input.addEventListener('click', function(){ this.select() }); | ||
// jump to page number from input when the input looses focus | ||
input.addEventListener('focusout', this.go); | ||
// … and when pressing enter inside the input | ||
input.addEventListener('keyup', function(e){ if (e.which === 13) this.go() }.bind(this)); | ||
|
||
} |
Oops, something went wrong.