Coverage for src/lektor_ng/pagination.py: 98%

54 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-08-08 10:40 +0000

1class Pagination: 

2 def __init__(self, record, pagination_config): 

3 #: the pagination config 

4 self.config = pagination_config 

5 #: the current page's record 

6 self.current = record 

7 #: the current page number (1 indexed) 

8 self.page = record.page_num 

9 #: the number of items to be displayed on a page. 

10 self.per_page = pagination_config.per_page 

11 #: the total number of items matching the query 

12 self.total = pagination_config.count_total_items(record) 

13 

14 @property 

15 def items(self): 

16 """The children for this page.""" 

17 return self.config.slice_query_for_page(self.current, self.page) 

18 

19 @property 

20 def pages(self): 

21 """The total number of pages.""" 

22 pages = (self.total + self.per_page - 1) // self.per_page 

23 # Even when there are no children, we want at least one page 

24 return max(pages, 1) 

25 

26 @property 

27 def prev_num(self): 

28 """The page number of the previous page.""" 

29 if self.page > 1: 

30 return self.page - 1 

31 return None 

32 

33 @property 

34 def has_prev(self): 

35 """True if a previous page exists.""" 

36 return self.page > 1 

37 

38 @property 

39 def prev(self): 

40 """The record for the previous page.""" 

41 if not self.has_prev: 

42 return None 

43 return self.config.get_record_for_page(self.current, self.page - 1) 

44 

45 @property 

46 def has_next(self): 

47 """True if a following page exists.""" 

48 return self.page < self.pages 

49 

50 @property 

51 def next_num(self): 

52 """The page number of the following page.""" 

53 if self.page < self.pages: 

54 return self.page + 1 

55 return None 

56 

57 @property 

58 def next(self): 

59 """The record for the following page.""" 

60 if not self.has_next: 

61 return None 

62 return self.config.get_record_for_page(self.current, self.page + 1) 

63 

64 def for_page(self, page): 

65 """Returns the record for a specific page.""" 

66 if 1 <= page <= self.pages: 

67 return self.config.get_record_for_page(self.current, page) 

68 return None 

69 

70 def iter_pages(self, left_edge=2, left_current=2, right_current=5, right_edge=2): 

71 """Iterate over the page numbers in the pagination, with elision. 

72 

73 In the general case, this returns the concatenation of three ranges: 

74 

75 1. A range (always starting at page one) at the beginning 

76 of the page number sequence. The length of the this 

77 range is specified by the ``left_edge`` argument (which 

78 may be zero). 

79 

80 2. A range around the current page. This range will 

81 include ``left_current`` pages before, and 

82 ``right_current`` pages after the current page. This 

83 range always includes the current page. 

84 

85 3. Finally, a range (always ending at the last page) at 

86 the end of the page sequence. The length of this range 

87 is specified by the ``right_edge`` argument. 

88 

89 If any of these ranges overlap, they will be merged. A 

90 ``None`` will be inserted between non-overlapping ranges to 

91 signify that pages have been elided. 

92 

93 This is how you could render such a pagination in the templates: 

94 .. sourcecode:: html+jinja 

95 {% macro render_pagination(pagination, endpoint) %} 

96 <div class=pagination> 

97 {%- for page in pagination.iter_pages() %} 

98 {% if page %} 

99 {% if page != pagination.page %} 

100 <a href="{{ url_for(endpoint, page=page) }}">{{ page }}</a> 

101 {% else %} 

102 <strong>{{ page }}</strong> 

103 {% endif %} 

104 {% else %} 

105 <span class=ellipsis>...</span> 

106 {% endif %} 

107 {%- endfor %} 

108 </div> 

109 {% endmacro %} 

110 

111 """ 

112 last = 0 

113 for num in range(1, self.pages + 1): 

114 # pylint: disable=chained-comparison 

115 if ( 

116 num <= left_edge 

117 or (num >= self.page - left_current and num <= self.page + right_current) 

118 or num > self.pages - right_edge 

119 ): 

120 if last + 1 != num: 

121 yield None 

122 yield num 

123 last = num 

124 if last != self.pages: 

125 yield None