diff --git a/docs/extras/plain.md b/docs/extras/plain.md index a98649c76..dd1fd1b63 100644 --- a/docs/extras/plain.md +++ b/docs/extras/plain.md @@ -96,48 +96,30 @@ The `:breakpoints` variable is a non-core variable used by the `responsive` navs For example: ```ruby -Pagy::VARS[:breakpoints] = { 0 => [1,0,0,1], 540 => [2,3,3,2], 720 => [3,4,4,3] } +Pagy::VARS[:breakpoints] = { 0 => [2,3,3,2], 540 => [3,5,5,3], 720 => [5,7,7,5] } ``` -The above statement means that from `0` to `540` pixels width, Pagy will use the `[1,0,0,1]` size, from `540` to `720` it will use the `[2,3,3,4]` size and over `720` it will use the `[3,4,4,3]` size. (Read more about the `:size` variable in the [How to control the page links](../how-to.md#controlling-the-page-links) section). +The above statement means that from `0` to `540` pixels width, Pagy will use the `[2,3,3,2]` size, from `540` to `720` it will use the `[3,5,5,3]` size and over `720` it will use the `[5,7,7,5]` size. (Read more about the `:size` variable in the [How to control the page links](../how-to.md#controlling-the-page-links) section). **IMPORTANT**: You can set any number of breakpoints with any arbitrary width and size. The only requirement is that the `:breakpoints` hash must contain always the `0` size. An `ArgumentError` exception will be raises if it is missing. -**Notice**: Each added breakpoint slowers down Pagy of almost 10%. For example: with 5 breakpoints (which are actually quite a lot) the nav will be rendered rougly in twice the normal time. However, that will still run about 15 times faster than Kaminari and 6 times faster than WillPaginate. +**Notice**: Each added breakpoint slowers down Pagy of less than 10%. For example: with 5 breakpoints the nav will be rendered rougly in less than twice the normal time. That will still run about 16 times faster than Kaminari and 7 times faster than WillPaginate, so it doesn't look like an issue. #### Setting the right breakpoints -Setting the width and the size of your breakpoint is what could create a nice transition between sizes... or some apparently erratic behavior. - -Here is what you should consider. - -The transition from one breakpoint/size to another depends by the width available to your nav. That width is the _internal available width_ of its container (excluding eventual horizontal padding), so the pagy breakpoint widths that you set should reflect the container internal available widths. - -The container width can change as a continous range (normal behavior for a div) or in discrete steps (for example when using bootstrap the container has classes like `sm-md-lg`). - -##### Continous Width-ranges +Setting the width and the size of your breakpoints is what can create a nice transition between sizes... or some apparently erratic behavior. -For continous width-range containers you should ensure that the resulting navs can be contained in the breakpoint widths that you set. In other words if you create a size as `[20,20,20,20]`, is pretty obvious that it could not be contained in a `540` width, so you should assign reasonable sizes based on the available widths. +Here is what you should consider/ensure: -##### Discrete Step Widths +1. The pagy size can only change in discreet steps: each widht/size pair in your `:breakpoints` represents a step. -If you use frameworks like bootstrap (but the same applies to many others) you can assign classes to your container that will snap to specific widths (e.g. `sm-md-lg`). In that case you should sync the quantity and widths of the pagy brakpoints to the quantity and internal container widths of the bootstrap classes. +2. The transition from one breakpoint/size to another depends on the width available to the pagy nav. That width is the _internal available width_ of its container (excluding eventual horizontal padding). -**IMPORTANT**: The pagy breakpoint widths should not be the same bootstrap breakpoints widths, but their container internal available widths. +3. You should ensure that each pagy `:size` in your breakpoints produces a nav that can be contained in its its width. -For example: if you assign the following classes: +4. You should ensure that the minimum internal width for the container div be equal (or a bit bigger) to the smaller positive `:breakpoints` width. (`540` pixels in our previous example). -``` -sm = Small ≥576px -Max container width 540px - -md = Medium ≥768px -Max container width 720px - -lg = Large ≥992px -Max container width 960px -``` -You should use the `0`, `540` and `720` width (or less if there is padding), and assign consistent sizes. +5. If the container width snaps to specific widths in discrete steps, you should sync the quantity and widths of the pagy `:brakpoints` to the quantity and internal widths for each discrete step of the container. ## Methods diff --git a/lib/config/pagy.rb b/lib/config/pagy.rb index 467333dc7..9aefb612d 100644 --- a/lib/config/pagy.rb +++ b/lib/config/pagy.rb @@ -60,8 +60,8 @@ # Breakpoints var used by the responsive nav helpers # See https://ddnexus.github.io/pagy/extras/plain#breakpoints -# width/size pairs: example for bootstrap4 sm-md-lg internal container widths -# Pagy::VARS[:breakpoints] = { 0 => [1,0,0,1], 540 => [2,3,3,2], 720 => [3,4,4,3] } +# Pagy::VARS[:breakpoints] = { 0 => [2,3,3,2], 540 => [3,5,5,3], 720 => [5,7,7,5] } + # Feature Extras diff --git a/lib/javascripts/pagy.js b/lib/javascripts/pagy.js index b1ab3ab68..d5ea05c78 100644 --- a/lib/javascripts/pagy.js +++ b/lib/javascripts/pagy.js @@ -53,27 +53,29 @@ Pagy.responsive = function(id, tags, widths, series){ var pagyEl = document.getElementById(id), container = pagyEl.parentElement, lastWidth = undefined, - resizeId = 0, + timeoutId = 0, render = function(){ - if (container.clientWidth === 0){ clearTimeout(resizeId); return setTimeout(render, 300) } - var width = widths.find(function(w) {return container.clientWidth > w}); + if (container.clientWidth === 0) { rendering() } + var width, i, len; + for (i = 0, len = widths.length; i < len; i++) { + if (container.clientWidth > widths[i]) { width = widths[i]; break } + } if (width !== lastWidth) { while (pagyEl.firstChild) { pagyEl.removeChild(pagyEl.firstChild) } - var html = tags['before']; - series[width].forEach(function(item) {html += tags[item]}); + var html = tags['before'], + items = series[width]; + for (i = 0, len = items.length; i < len; i++) { html += tags[items[i]] } html += tags['after']; pagyEl.insertAdjacentHTML('beforeend', html); lastWidth = width; } }, - resize = function(){ // call render once, after window.resize is done - clearTimeout(resizeId); - resizeId = setTimeout(render, 300); - }; - // remove the previous window resize listener which may result in firing the render multiple times + // suppress rapid firing rendering + rendering = function(){ clearTimeout(timeoutId); timeoutId = setTimeout(render, 150) }; + // refresh the window resize listener (avoiding rendering multiple times) window.removeEventListener('resize', Pagy.windowListeners[id], true); - window.addEventListener('resize', resize, true); - Pagy.windowListeners[id] = resize; + window.addEventListener('resize', rendering, true); + Pagy.windowListeners[id] = rendering; render(); }; diff --git a/lib/pagy/extras/shared.rb b/lib/pagy/extras/shared.rb index 24cca11a4..85d117e87 100644 --- a/lib/pagy/extras/shared.rb +++ b/lib/pagy/extras/shared.rb @@ -14,9 +14,9 @@ class Pagy # Pagy.new count:1000, page: 20, breakpoints: {0 => [1,2,2,1], 350 => [2,3,3,2], 550 => [3,4,4,3]} # it returns something like: # { :items => [1, :gap, 18, 19, "20", 21, 22, 50, 2, 17, 23, 49, 3, 16, 24, 48], - # :series => { 0 =>[1, :gap, 18, 19, "20", 21, 22, :gap, 50], - # 350 =>[1, 2, :gap, 17, 18, 19, "20", 21, 22, 23, :gap, 49, 50], - # 550 =>[1, 2, 3, :gap, 16, 17, 18, 19, "20", 21, 22, 23, 24, :gap, 48, 49, 50] }, + # :series => { 0 => [1, :gap, 18, 19, "20", 21, 22, :gap, 50], + # 350 => [1, 2, :gap, 17, 18, 19, "20", 21, 22, 23, :gap, 49, 50], + # 550 => [1, 2, 3, :gap, 16, 17, 18, 19, "20", 21, 22, 23, 24, :gap, 48, 49, 50] }, # :widths => [550, 350, 0] } # where :items is the unordered array union of all the page numbers for all sizes (passed to the PagyResponsive javascript function) # :series is the hash of the series keyed by width (used by the *_responsive helpers to create the JSON string)