From 3cce19a660ef9f32ad048d5df409d1568f731c97 Mon Sep 17 00:00:00 2001
From: Domizio Demichelis
Date: Sun, 24 Mar 2019 12:14:26 +0700
Subject: [PATCH] javascript responsive refactoring:
- replaced problematic loop functions with plain for loops
- better naming in responsive function
- shortened rendering time
- simpler doc
---
docs/extras/plain.md | 38 ++++++++++----------------------------
lib/config/pagy.rb | 4 ++--
lib/javascripts/pagy.js | 26 ++++++++++++++------------
lib/pagy/extras/shared.rb | 6 +++---
4 files changed, 29 insertions(+), 45 deletions(-)
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)