Added the navigation links for pagination.
This commit is contained in:
parent
3bce775729
commit
19ac9d3200
@ -34,6 +34,8 @@ First written: 2020/7/1
|
|||||||
<p>{{ request.resolver_match.app_name }}</p>
|
<p>{{ request.resolver_match.app_name }}</p>
|
||||||
|
|
||||||
{% if records %}
|
{% if records %}
|
||||||
|
{% include "mia_core/pagination.html" %}
|
||||||
|
|
||||||
{# The table for large screens #}
|
{# The table for large screens #}
|
||||||
<table class="table table-striped table-hover d-none d-md-table general-journal-table">
|
<table class="table table-striped table-hover d-none d-md-table general-journal-table">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -201,5 +201,5 @@ ORDER BY
|
|||||||
self.kwargs["subject_code"] + "%",
|
self.kwargs["subject_code"] + "%",
|
||||||
self.kwargs["subject_code"] + "%"])
|
self.kwargs["subject_code"] + "%"])
|
||||||
self.pagination = Pagination(
|
self.pagination = Pagination(
|
||||||
records, self.page_no, self.page_size, True)
|
self.request, records, self.page_no, self.page_size, True)
|
||||||
return self.pagination.records
|
return self.pagination.records
|
||||||
|
38
mia_core/templates/mia_core/pagination.html
Normal file
38
mia_core/templates/mia_core/pagination.html
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{% comment %}
|
||||||
|
The Mia Website
|
||||||
|
base.html: The side-wide layout template
|
||||||
|
|
||||||
|
Copyright (c) 2020 imacat.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
Author: imacat@mail.imacat.idv.tw (imacat)
|
||||||
|
First written: 2020/7/1
|
||||||
|
{% endcomment %}
|
||||||
|
|
||||||
|
{# The pagination, if any #}
|
||||||
|
{% if pagination.is_paged %}
|
||||||
|
<ul class="pagination">
|
||||||
|
{% for link in pagination.links %}
|
||||||
|
{% if link.url is not None %}
|
||||||
|
<li class="page-item {% if link.is_active %} active {% endif %}{% if not link.is_small_screen %} d-none d-md-inline {% endif %}">
|
||||||
|
<a class="page-link" href="{{ link.url }}">{{ link.title }}</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled {% if link.is_active %} active {% endif %}{% if not link.is_small_screen %} d-none d-md-inline {% endif %}">
|
||||||
|
<span class="page-link">{{ link.title }}</span>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
|
|
||||||
|
from django.utils.translation import pgettext
|
||||||
|
|
||||||
|
|
||||||
class UrlBuilder:
|
class UrlBuilder:
|
||||||
"""The URL builder.
|
"""The URL builder.
|
||||||
@ -91,6 +93,17 @@ class UrlBuilder:
|
|||||||
"""
|
"""
|
||||||
return self.del_param(name).add_param(name, value)
|
return self.del_param(name).add_param(name, value)
|
||||||
|
|
||||||
|
def clone(self):
|
||||||
|
"""Returns a copy of this URL builder.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
UrlBuilder: A copy of this URL builder.
|
||||||
|
"""
|
||||||
|
another = UrlBuilder(self.base_path)
|
||||||
|
another.params = [
|
||||||
|
self.Param(x.name, x.value) for x in self.params]
|
||||||
|
return another
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if len(self.params) == 0:
|
if len(self.params) == 0:
|
||||||
return self.base_path
|
return self.base_path
|
||||||
@ -134,42 +147,170 @@ class Pagination:
|
|||||||
"""The pagination.
|
"""The pagination.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
request (HttpRequest): The request
|
||||||
records (list[Model]): All the records
|
records (list[Model]): All the records
|
||||||
page_no (int): The specified page number
|
page_no (int): The specified page number
|
||||||
page_size (int): The specified number of records per page
|
page_size (int): The specified number of records per page
|
||||||
is_reverse (bool): Whether we should display the last
|
is_reversed (bool): Whether we should display the last
|
||||||
page first
|
page first
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
PageNoOutOfRangeError: if the specified page number is out
|
PageNoOutOfRangeError: if the specified page number is out
|
||||||
of range or is redundant.
|
of range or is redundant.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
page_no (int): The current page number
|
is_reversed (bool): Whether we should display the last
|
||||||
page_size (int): The page size
|
page first
|
||||||
records (list[Model]): The records in the current page
|
page_size (int): The page size.
|
||||||
|
total_pages (int): The total number of pages available.
|
||||||
|
is_paged (bool): Whether there are more than one page.
|
||||||
|
page_no (int): The current page number.
|
||||||
|
records (list[Model]): The records in the current page.
|
||||||
|
links (list[Link]): The navigation links in the pagination
|
||||||
|
bar.
|
||||||
"""
|
"""
|
||||||
page_no = None
|
is_reversed = False
|
||||||
page_size = None
|
page_size = None
|
||||||
|
total_pages = None
|
||||||
|
is_paged = None
|
||||||
|
page_no = None
|
||||||
records = None
|
records = None
|
||||||
|
links = None
|
||||||
|
|
||||||
DEFAULT_PAGE_SIZE = 10
|
DEFAULT_PAGE_SIZE = 10
|
||||||
|
|
||||||
def __init__(self, records, page_no, page_size, is_reverse=False):
|
def __init__(self, request, records, page_no,
|
||||||
|
page_size, is_reversed=False):
|
||||||
|
self.is_reversed = is_reversed
|
||||||
self.page_size = page_size \
|
self.page_size = page_size \
|
||||||
if page_size is not None \
|
if page_size is not None \
|
||||||
else self.DEFAULT_PAGE_SIZE
|
else self.DEFAULT_PAGE_SIZE
|
||||||
total_pages = int((len(records) - 1) / self.page_size) + 1
|
self.total_pages = int(
|
||||||
default_page = 1 if not is_reverse else total_pages
|
(len(records) - 1) / self.page_size) + 1
|
||||||
|
self.is_paged = self.total_pages > 1
|
||||||
|
if not self.is_paged:
|
||||||
|
self.page_no = 1
|
||||||
|
self.records = records
|
||||||
|
self.links = []
|
||||||
|
return
|
||||||
|
default_page = 1 if not is_reversed else self.total_pages
|
||||||
if page_no == default_page:
|
if page_no == default_page:
|
||||||
raise PageNoOutOfRangeException()
|
raise PageNoOutOfRangeException()
|
||||||
self.page_no = page_no \
|
self.page_no = page_no \
|
||||||
if page_no is not None \
|
if page_no is not None \
|
||||||
else default_page
|
else default_page
|
||||||
if self.page_no > total_pages:
|
if self.page_no > self.total_pages:
|
||||||
raise PageNoOutOfRangeException()
|
raise PageNoOutOfRangeException()
|
||||||
start_no = self.page_size * (self.page_no - 1)
|
start_no = self.page_size * (self.page_no - 1)
|
||||||
self.records = records[start_no:start_no + self.page_size]
|
self.records = records[start_no:start_no + self.page_size]
|
||||||
|
self.create_pagination_bar(request)
|
||||||
|
|
||||||
|
def create_pagination_bar(self, request):
|
||||||
|
"""Creates the pagination bar.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request (HttpRequest): The request
|
||||||
|
"""
|
||||||
|
base_url = UrlBuilder(
|
||||||
|
request.get_full_path()).del_param("page")
|
||||||
|
self.links = []
|
||||||
|
# The previous page
|
||||||
|
link = self.Link()
|
||||||
|
link.title = pgettext("Pagination|", "Previous")
|
||||||
|
if self.page_no > 1:
|
||||||
|
if self.page_no - 1 == 1:
|
||||||
|
if not self.is_reversed:
|
||||||
|
link.url = str(base_url)
|
||||||
|
else:
|
||||||
|
link.url = str(base_url.clone().add_param(
|
||||||
|
"page", "1"))
|
||||||
|
else:
|
||||||
|
link.url = str(base_url.clone().add_param(
|
||||||
|
"page", str(self.page_no - 1)))
|
||||||
|
link.is_small_screen = True
|
||||||
|
self.links.append(link)
|
||||||
|
# The first page
|
||||||
|
link = self.Link()
|
||||||
|
link.title = "1"
|
||||||
|
if not self.is_reversed:
|
||||||
|
link.url = str(base_url)
|
||||||
|
else:
|
||||||
|
link.url = str(base_url.clone().add_param("page", "1"))
|
||||||
|
if self.page_no == 1:
|
||||||
|
link.is_active = True
|
||||||
|
self.links.append(link)
|
||||||
|
# The previous ellipsis
|
||||||
|
if self.page_no > 4:
|
||||||
|
link = self.Link()
|
||||||
|
if self.page_no > 5:
|
||||||
|
link.title = pgettext("Pagination|", "...")
|
||||||
|
else:
|
||||||
|
link.title = "2"
|
||||||
|
link.url = str(base_url.clone().add_param(
|
||||||
|
"page", "2"))
|
||||||
|
self.links.append(link)
|
||||||
|
# The nearby pages
|
||||||
|
for no in range(self.page_no - 2, self.page_no + 3):
|
||||||
|
if no <= 1 or no >= self.total_pages:
|
||||||
|
continue
|
||||||
|
link = self.Link()
|
||||||
|
link.title = str(no)
|
||||||
|
link.url = str(base_url.clone().add_param(
|
||||||
|
"page", str(no)))
|
||||||
|
if no == self.page_no:
|
||||||
|
link.is_active = True
|
||||||
|
self.links.append(link)
|
||||||
|
# The next ellipsis
|
||||||
|
if self.page_no + 3 < self.total_pages:
|
||||||
|
link = self.Link()
|
||||||
|
if self.page_no + 4 < self.total_pages:
|
||||||
|
link.title = pgettext("Pagination|", "...")
|
||||||
|
else:
|
||||||
|
link.title = str(self.total_pages - 1)
|
||||||
|
link.url = str(base_url.clone().add_param(
|
||||||
|
"page", str(self.total_pages - 1)))
|
||||||
|
self.links.append(link)
|
||||||
|
# The last page
|
||||||
|
link = self.Link()
|
||||||
|
link.title = str(self.total_pages)
|
||||||
|
if self.is_reversed:
|
||||||
|
link.url = str(base_url)
|
||||||
|
else:
|
||||||
|
link.url = str(base_url.clone().add_param(
|
||||||
|
"page", str(self.total_pages)))
|
||||||
|
if self.page_no == self.total_pages:
|
||||||
|
link.is_active = True
|
||||||
|
self.links.append(link)
|
||||||
|
# The next page
|
||||||
|
link = self.Link()
|
||||||
|
link.title = pgettext("Pagination|", "Next")
|
||||||
|
if self.page_no < self.total_pages:
|
||||||
|
if self.page_no + 1 == self.total_pages:
|
||||||
|
if self.is_reversed:
|
||||||
|
link.url = str(base_url)
|
||||||
|
else:
|
||||||
|
link.url = str(base_url.clone().add_param(
|
||||||
|
"page", str(self.total_pages)))
|
||||||
|
else:
|
||||||
|
link.url = str(base_url.clone().add_param(
|
||||||
|
"page", str(self.page_no + 1)))
|
||||||
|
link.is_small_screen = True
|
||||||
|
self.links.append(link)
|
||||||
|
|
||||||
|
class Link:
|
||||||
|
"""A navigation link in the pagination bar.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
url (str): The link URL, or for a non-link slot.
|
||||||
|
title (str): The title of the link.
|
||||||
|
is_active (bool): Whether this link is currently active.
|
||||||
|
is_small_screen (bool): Whether this link is for small
|
||||||
|
screens
|
||||||
|
"""
|
||||||
|
url = None
|
||||||
|
title = None
|
||||||
|
is_active = False
|
||||||
|
is_small_screen = False
|
||||||
|
|
||||||
|
|
||||||
class PageNoOutOfRangeException(Exception):
|
class PageNoOutOfRangeException(Exception):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user