blakeembrey / metalsmith-pagination

A Metalsmith plugin for paginating arrays and collections
MIT License
34 stars 10 forks source link

cycle through num pages at a time #12

Closed ninjasort closed 8 years ago

ninjasort commented 8 years ago

What would be the best way to approach pagination links that show 5 items at a time and move the offset every 6th page? Thanks.

blakeembrey commented 8 years ago

I'm not sure I follow this part: "move the offset every 6th page". Could you describe more of what you're trying to do? Are you saying you want to show "1-5", then "6-10", etc. without moving the displayed pages in the middle (e.g. on page 5 it still shows "1-5")?

ninjasort commented 8 years ago

Yeah, showing 1-5, 6-10, 11-15, etc. Every 6th page would rotate the grouping.

blakeembrey commented 8 years ago

It should be pretty simple math.

var firstPage = Math.floor(currentPage / 6) * 6

Then do a loop the size of the pages forward. Feel free ask more questions :smile:

ninjasort commented 8 years ago

Sorry, how did you come up with that equation?

blakeembrey commented 8 years ago

Honestly, I guess intuition? Well, you wanted to have "ranges" of pagination - so that means finding the first page. Assuming the range is 6 pages, you need to get 3 = 0, 9 = 1, ... Then it's just a matter of knowing how to do that, which (one way) is dividing the current page by the range, then multiplying it by the range again to get the lower bound of what you want. I don't know if this helps though?

ninjasort commented 8 years ago

Doesn't that just give you the current index though? What if you only want a new set after you've passed the 5th page?

ninjasort commented 8 years ago

Is there no way to just build this in? pagination.group {% for page in pagination.group %}

blakeembrey commented 8 years ago

Divide by 5, multiply by 5. It gives you the current index, yes. You can then get the page, whatever you need to do. No, I don't see why it needs to be built in - it's simple and non-standard, I can't think of any pagination that acts like you describe.

ninjasort commented 8 years ago

I'm using liquid and I have the following:

{% for page in pagination.pages | limit:5 %}
                  <li>
                    <a class="{% if pagination.num == page.pagination.num %}active{% endif %}" href="/{{ page.path }}">
                      {{ page.pagination.num }}
                    </a>
                  </li>
{% endfor %}

This outputs 1,2,3,4,5 but when I click next it goes to 2,3,4,5,6. Having a pagination.group would allow someone to set a limit and bound so that way you could just do:

{% for page in pagination.group %}
                  <li>
                    <a class="{% if pagination.num == page.pagination.num %}active{% endif %}" href="/{{ page.path }}">
                      {{ page.pagination.num }}
                    </a>
                  </li>
{% endfor %}

And you'd get [1],2,3,4,5 then 1,[2],3,4,5 all the way until the 6th page, which would shift the bound and select the next group 6,7,8,9,10. This way, similarly to pagination.index, you get a the active group by bound instead of needing to create a collection from template logic.

ninjasort commented 8 years ago

It's definitely a common use case for pagination. When do you ever just see one link for pagination when using numbers?

blakeembrey commented 8 years ago

@cameronjroe But it's never really you're implementation. If you look at some pagination sections, it's typically centered, not the odd segmented behavior:

image

blakeembrey commented 8 years ago

When do you ever just see one link for pagination when using numbers?

I have no idea what this comment is about. Obviously pagination needs more numbers, I feel like that's been established. For custom pagination behavior like yours, just write a custom for loop.

var count = 5
var start = Math.floor(currentIndex / count) * count

for (var i = start; i < pages.length; i++) {
  // Do stuff.
}

I don't use liquid so you'll need to figure out how to write that in your template engine. Or just change the data before you render it.

ninjasort commented 8 years ago

http://www.sitepoint.com/page/10/

ninjasort commented 8 years ago

This is a plugin though, wouldn't it be ideal to abstract template logic into a few simple variables to pass in. I'm not working within js, and most people won't be since metalsmith templating is done with handlebars or liquid.

blakeembrey commented 8 years ago

Cool. But I'd still just code it. Isn't your current code wrong right now? It looks like your always limiting it to 5? Can you do function calls in your template engine?

blakeembrey commented 8 years ago

If you wish to do a PR, go ahead.

blakeembrey commented 8 years ago

If you do a PR, please follow the current behavior getPages.

ninjasort commented 8 years ago

I can get it to work in the template logic, but all I'm really confused about is how to get the pagination.index by fives.

blakeembrey commented 8 years ago
var start = Math.floor(currentIndex / 5) * 5
ninjasort commented 8 years ago

That doesn't work. And it already exists on pagination.index. I need the same set of pages when pagination.index == 1,2,3,4,5. Then when pagination.index == 6,7,8,9,10, I need the next set of pages.

blakeembrey commented 8 years ago

What are you saying? The above is example code. What exists on pagination.index? That literally is currentIndex in my code examples. Please use StackOverflow in the future, I don't have all day to answer general math questions. My understanding from what you've said is exactly what I've posted.

var pages = 5
var start = Math.floor(pagination.index / pages) * pages
var end = Math.min(start + pages, pagination.pages.length)

for (var i = start; i < end; i++) {
  // Do something with the page at this index.
}
ninjasort commented 8 years ago

This was actually what I was looking for:

{% assign mod = pagination.index | modulo:5 %}
                {% assign diff = pagination.index | minus:mod %}
                {% assign end = diff | plus:4 %}
                {% for index in (diff..end) %}
                  {% assign page = pagination.pages | get:index %}
                  <li>
                    <a class="{% if pagination.num == page.pagination.num %}active{% endif %}" href="/{{ page.path }}">
                      {{ page.pagination.num }}
                    </a>
                  </li>
                {% endfor %}
blakeembrey commented 8 years ago

Looks good. That's why I asked if you could use functions, because I'm not familiar with your template library. That's pretty much the same logic as above, just in your custom form, so if you can't use functions it might not be helpful even if it's built in (as it'd require a function call).

(Math.floor(12 / 5) * 5) === (12 - (12 % 5))
ninjasort commented 8 years ago

Ideally this would just exist as I showed above:

var pagination = require('metalsmith-pagination')

metalsmith.use(pagination({
  'collections.articles': {
    perPage: 5,
    template: 'blog.liquid',
    first: 'index.html',
    cycleLength: 5, // creates a cycle of 5 pages at a time that change when modulo cycles through every 5th item
    path: 'page/:num/index.html',
    pageMetadata: {
      title: 'Archive'
    }
  }
}))

It would also be super convenient to just have the active class as either a string 'active' or '' depending on if the index is the current index. page.activeClass

{% for page in pagination.group %}
  <li>
    <a class="{{ page.pagination.activeClass }}" href="/{{ page.path }}">
      {{ page.pagination.num }}
    </a>
  </li>
{% endfor %}