eleventy icon indicating copy to clipboard operation
eleventy copied to clipboard

#1036 Add skip parameter to pagination plugin

Open Snapstromegon opened this issue 3 years ago • 8 comments

This PR adds an option to skip the first n items of a pagination. This allows usecases as described in #1036, where one might want to show the first n items on onether page and then paginate over the rest.

fixes #1036

Snapstromegon avatar Jun 29 '22 20:06 Snapstromegon

Huh! So this is like a start index?

zachleat avatar Jun 29 '22 21:06 zachleat

Yeah right. Basically it's a wrapper around [].slice().

Snapstromegon avatar Jun 29 '22 21:06 Snapstromegon

Do we need test(s) for skip + the before callback as well? Curious if the skip would occur before or after the before callback.

pdehaan avatar Jun 29 '22 21:06 pdehaan

@pdehaan I added only one happy path and one sad path test for skip in this PR.

Also the behavior is described in the docs PR: https://github.com/11ty/11ty-website/pull/1440 Basically it happens last, since it should take effect after reversing and filtering.

Snapstromegon avatar Jun 29 '22 21:06 Snapstromegon

Personally I'm unsure about the name 'skip'.

FWIW there's a few other related options pagination could have - start index, end index, count. I've had a few cases where I've wanted to limit or truncate my set of options.

One possible way of supporting all of these could be for a range parameter.

edwardhorsford avatar Jan 05 '24 10:01 edwardhorsford

@edwardhorsford Ahh, that might be a good idea. I came from the point of the SQL "SKIP" command. How would you make this range parameter?

My first suggestion would be something like this:

range:
  first: 3
  last: -4
  count: 5

Where negative values mean "from last", where "-1" means the last element similar to Array.at(). Count is considered a max.

  • If only first is set, it's like [].slice(first).
  • If first and count is set, it's like [].slice(first, first+count)
  • If only first and last is set, it's like [].slice(first, last+1)
  • If count is set, it's like [].slice(0, count)
  • if last is set, it's like [].slice(last)
  • if last and count is set, it's like [].slice(last, last-count)
  • If all three are set, it's like [].slice(first, last+1).slice(0, count)

Additionally we could support a string value for range in the form of Rust Ranges, so range: 0..5 or range: 0..=4. Here the first number is read as "first" from above and the second as "last" (for ..= or last-1 for ..).

Snapstromegon avatar Jan 05 '24 10:01 Snapstromegon

@Snapstromegon yep, I had a similar thought - using negative numbers to count backwards for the end.

I suspect your first example with an object and properties is easier to read and understand than the Rust ranges.

I might suggest different names though... perhaps:

range:
  start: 10
  end: -4
  limit: 100

I suspect users would be unlikely to want to use both end and limit simultaneously, but seems fine to support both as long as the priority is clear.

I speculate count might be misread as an expectation that number of pages should be generated - when in reality it's either a limit or truncation.

My main use for a limit so far has been where I'm working on a pagination file that outputs many hundreds of pages - but for development I only need a small number to test. My solution so far has been filtering the data with the before callback.

edwardhorsford avatar Jan 05 '24 13:01 edwardhorsford

@edwardhorsford limit sounds better. I also think of supporting the range and object syntax at the same time, so it's not one or the other (this is, so the simpler way of start and end can be shorter).

I also think that limit is fairly good semantically coming from SQL, since it clearly transports the priority (first select by start and end, then only take the limit amount).

What I personally disagree with, is that start and end are better names, because first and last clearly state wether or not the selected range is inclusive or not.

E.g. if I have this data:

- zero
- one
- two
- three
- four
- five
- six
- seven

And I'd do

range:
  start: 2
  end: 4

Would I get ['two', 'three'] or ['two', 'three', 'four']? (I would keep this similar to [].slice() and make the range non-inclusive.

Snapstromegon avatar Jan 05 '24 13:01 Snapstromegon