Skip to content

Instantly share code, notes, and snippets.

@m1el
Last active January 7, 2021 14:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save m1el/c4d9c366a38d6b6d4faea8eedf1b4ce2 to your computer and use it in GitHub Desktop.
Save m1el/c4d9c366a38d6b6d4faea8eedf1b4ce2 to your computer and use it in GitHub Desktop.
pub struct PaginationConfig {
pub items_around_current: usize,
pub items_at_ends: usize,
pub minimum_skip: usize,
}
#[derive(Debug)]
pub enum PaginationItem {
PageNumber(usize),
Ellipsis,
}
pub const PAGINATION_DEFAULT_CONFIG: PaginationConfig = PaginationConfig {
items_around_current: 2,
items_at_ends: 1,
minimum_skip: 2,
};
fn generate_pagination(current_page: usize, page_count: usize)
-> Vec<PaginationItem>
{
generate_pagination_with_config(current_page, page_count, PAGINATION_DEFAULT_CONFIG)
}
fn generate_pagination_with_config(
current_page: usize, page_count: usize, config: PaginationConfig)
-> Vec<PaginationItem>
{
use PaginationItem::*;
let pages_on_screen = (config.items_at_ends + config.minimum_skip
+ config.items_around_current - 1) * 2 + 1;
if page_count < pages_on_screen {
return (1..page_count).map(PageNumber).collect();
}
let skip_edge = config.items_at_ends + config.minimum_skip;
let items_minimum = (config.items_around_current * 2 + 1)
.max(config.items_at_ends);
let edge_items = items_minimum + skip_edge - 1;
let start = current_page.saturating_sub(config.items_around_current)
.clamp(1, page_count + 1 - edge_items);
let end = (current_page + config.items_around_current)
.clamp(edge_items, page_count);
let mut result = Vec::with_capacity(pages_on_screen);
if start <= skip_edge {
result.extend((1..start).map(PageNumber));
} else {
result.extend((1..=config.items_at_ends).map(PageNumber));
result.push(Ellipsis);
}
result.extend((start..=end).map(PageNumber));
if page_count + 1 - end <= skip_edge {
result.extend((end + 1..=page_count).map(PageNumber));
} else {
result.push(Ellipsis);
result.extend(
(page_count - config.items_at_ends + 1..=page_count).map(PageNumber));
}
return result;
}
fn main() {
for ii in 1..=12 {
println!("{:?}", generate_pagination(ii, 12));
}
}
IEnumerable<int> GeneratePagination(int currentPage, int pageCount) {
var itemsAroundCurrent = 1;
var itemsAtEnds = 1;
var minimumSkip = 2;
var pagesOnScreen = (itemsAtEnds + minimumSkip + itemsAroundCurrent - 1) * 2 + 1;
if (pageCount <= pagesOnScreen) {
return Enumerable.Range(1, pagesOnScreen);
}
var skipEdge = itemsAtEnds + minimumSkip;
var itemsMinimum = Math.Max(itemsAroundCurrent * 2 + 1, itemsAtEnds);
var start = Math.Clamp(currentPage - itemsAroundCurrent, 1, pageCount + 2 - itemsMinimum - skipEdge);
var end = Math.Clamp(currentPage + itemsAroundCurrent, itemsMinimum + skipEdge - 1, pageCount);
var result = new List<int>(pagesOnScreen);
if (start <= skipEdge) {
result.AddRange(Enumerable.Range(1, start - 1));
} else {
result.AddRange(Enumerable.Range(1, itemsAtEnds));
result.Add(0);
}
result.AddRange(Enumerable.Range(start, end - start + 1));
if (pageCount + 1 - end <= skipEdge) {
result.AddRange(Enumerable.Range(end + 1, pageCount - end));
} else {
result.Add(0);
result.AddRange(Enumerable.Range(pageCount - itemsAtEnds + 1, itemsAtEnds));
}
return result;
}
void Main()
{
Console.WriteLine(string.Join(", ", GeneratePagination(1, 12)));
Console.WriteLine(string.Join(", ", GeneratePagination(4, 12)));
Console.WriteLine(string.Join(", ", GeneratePagination(5, 12)));
Console.WriteLine(string.Join(", ", GeneratePagination(6, 12)));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment