diff --git a/Ion.egg-info/SOURCES.txt b/Ion.egg-info/SOURCES.txt index f3c136eec33..15bc8da03f5 100644 --- a/Ion.egg-info/SOURCES.txt +++ b/Ion.egg-info/SOURCES.txt @@ -790,6 +790,7 @@ intranet/apps/templatetags/form_field.py intranet/apps/templatetags/forms.py intranet/apps/templatetags/math.py intranet/apps/templatetags/newtab_links.py +intranet/apps/templatetags/paginate.py intranet/apps/templatetags/strings.py intranet/apps/templatetags/tests.py intranet/apps/users/__init__.py diff --git a/docs/sourcedoc/intranet.apps.templatetags.rst b/docs/sourcedoc/intranet.apps.templatetags.rst index 398cd476472..a5820320a6b 100644 --- a/docs/sourcedoc/intranet.apps.templatetags.rst +++ b/docs/sourcedoc/intranet.apps.templatetags.rst @@ -52,6 +52,14 @@ intranet.apps.templatetags.newtab\_links module :undoc-members: :show-inheritance: +intranet.apps.templatetags.paginate module +------------------------------------------ + +.. automodule:: intranet.apps.templatetags.paginate + :members: + :undoc-members: + :show-inheritance: + intranet.apps.templatetags.strings module ----------------------------------------- diff --git a/intranet/apps/dashboard/views.py b/intranet/apps/dashboard/views.py index f3bc81b13d9..1f0e455cf11 100644 --- a/intranet/apps/dashboard/views.py +++ b/intranet/apps/dashboard/views.py @@ -4,6 +4,7 @@ from django.conf import settings from django.contrib.auth.decorators import login_required +from django.core.paginator import Paginator from django.shortcuts import redirect, render from django.urls import reverse from django.utils import timezone @@ -255,39 +256,42 @@ def get_announcements_list(request, context): midnight = timezone.localtime().replace(hour=0, minute=0, second=0, microsecond=0) events = Event.objects.visible_to_user(user).filter(time__gte=midnight, show_on_dashboard=True) - items = sorted(chain(announcements, events), key=lambda item: (item.pinned, item.added)) - items.reverse() + def announcements_sorting_key(item): + if context["show_expired"] or context["show_all"]: + return item.added + # otherwise sort by pinned and then added date + return (item.pinned, item.added) + + items = sorted(chain(announcements, events), key=announcements_sorting_key, reverse=True) return items def paginate_announcements_list(request, context, items): """ - ***TODO*** Migrate to django Paginator (see lostitems) + Paginate ``items`` in groups of 15 """ + DEFAULT_PAGE_NUM = 1 - # pagination - if "start" in request.GET: - try: - start_num = int(request.GET.get("start")) - except ValueError: - start_num = 0 + if request.GET.get("page", "INVALID").isdigit(): + page_num = int(request.GET["page"]) else: - start_num = 0 + page_num = DEFAULT_PAGE_NUM - display_num = 15 - end_num = start_num + display_num - prev_page = start_num - display_num - more_items = (len(items) - start_num) > display_num - try: - items_sorted = items[start_num:end_num] - except (ValueError, AssertionError): - items_sorted = items[:display_num] - else: - items = items_sorted + paginator = Paginator(items, 15) + if page_num not in paginator.page_range: + page_num = DEFAULT_PAGE_NUM - context.update({"items": items, "start_num": start_num, "end_num": end_num, "prev_page": prev_page, "more_items": more_items}) + items = paginator.page(page_num) + + more_items = items.has_next() + prev_page = items.previous_page_number() if items.has_previous() else 0 + next_page = items.next_page_number() if more_items else 0 + + context.update( + {"items": items, "page_num": page_num, "prev_page": prev_page, "next_page": next_page, "more_items": more_items, "page_obj": paginator} + ) return context, items @@ -431,8 +435,6 @@ def dashboard_view(request, show_widgets=True, show_expired=False, ignore_dashbo # Show all by default to 8th period office show_all = True - # Include show_all postfix on next/prev links - paginate_link_suffix = "&show_all=1" if show_all else "" is_index_page = request.path_info in ["/", ""] context = { @@ -442,7 +444,6 @@ def dashboard_view(request, show_widgets=True, show_expired=False, ignore_dashbo "events_admin": events_admin, "is_index_page": is_index_page, "show_all": show_all, - "paginate_link_suffix": paginate_link_suffix, "show_expired": show_expired, "show_tjstar": settings.TJSTAR_BANNER_START_DATE <= now.date() <= settings.TJSTAR_DATE, } diff --git a/intranet/apps/templatetags/paginate.py b/intranet/apps/templatetags/paginate.py new file mode 100644 index 00000000000..22eed86ca88 --- /dev/null +++ b/intranet/apps/templatetags/paginate.py @@ -0,0 +1,46 @@ +from typing import List, Union + +from django import template + +register = template.Library() + + +@register.simple_tag +def query_transform(request, **kwargs): + query = request.GET.copy() + for k, v in kwargs.items(): + query[k] = v + return query.urlencode() + + +@register.filter # TODO: replace return type with list[int | None] +def page_list(paginator, current_page) -> List[Union[int, None]]: + """Pagination + + If there is a ``None`` in the output, it should be replaced + with ...'s. + """ + SURROUNDING_PAGES = 2 + BEGINNING_PAGES = 2 + END_PAGES = 2 + total_pages = paginator.page_range + + # The page numbers to show + actual_numbers = [ + page + for page in total_pages + if ( + page >= total_pages[-1] - END_PAGES + 1 + or page <= BEGINNING_PAGES + or (current_page.number - SURROUNDING_PAGES <= page <= current_page.number + SURROUNDING_PAGES) + ) + ] + + pages = [] + for i, number in enumerate(actual_numbers[:-1]): + pages.append(number) + # if there is a mismatch, that means we should add a ... + if actual_numbers[i + 1] != number + 1: + pages.append(None) + pages.append(actual_numbers[-1]) + return pages diff --git a/intranet/static/css/dark/dashboard.widgets.scss b/intranet/static/css/dark/dashboard.widgets.scss index df8727cc6b8..f7302eb53b0 100644 --- a/intranet/static/css/dark/dashboard.widgets.scss +++ b/intranet/static/css/dark/dashboard.widgets.scss @@ -16,3 +16,7 @@ .btn-link { border-color: $darkborder; } + +.ellipses { + --ellipses-color: white; +} diff --git a/intranet/static/css/dashboard.widgets.scss b/intranet/static/css/dashboard.widgets.scss index 6ae58349fe0..e2d1c018e15 100644 --- a/intranet/static/css/dashboard.widgets.scss +++ b/intranet/static/css/dashboard.widgets.scss @@ -483,6 +483,35 @@ a.btn-link { } } +/* Pagination */ +.ellipses { + padding: 7px 10px; + margin: 2px 0; + font-size: 13px; + font-weight: bold; + --ellipses-color: $grey; + color: var(--ellipses-color); + + &:hover { + color: var(--ellipses-color); + text-decoration: none; + // don't change cursor while hovering on + // ...'s in pagination + cursor: default; + } + + &:visited { + color: var(--ellipses-color); + } +} + +.button:disabled, +.button[disabled] +{ + opacity: 0.4; + pointer-events: none; +} + /* BIRTHDAYS */ .birthdays-widget { diff --git a/intranet/static/js/dashboard/common.js b/intranet/static/js/dashboard/common.js index 9885190d53b..ada15b2ac3d 100644 --- a/intranet/static/js/dashboard/common.js +++ b/intranet/static/js/dashboard/common.js @@ -12,6 +12,8 @@ $(function() { if(e.keyCode === 9) { e.preventDefault(); } - $("#searchbox").focus(); + if(!$(".dashboard-textinput").is(":focus")) { + $("#searchbox").focus(); + } }); }); diff --git a/intranet/templates/dashboard/dashboard.html b/intranet/templates/dashboard/dashboard.html index b391384028b..09c67caabb3 100644 --- a/intranet/templates/dashboard/dashboard.html +++ b/intranet/templates/dashboard/dashboard.html @@ -3,6 +3,7 @@ {% load dates %} {% load cacheops %} {% load pipeline %} +{% load paginate %} {% block title %} {{ block.super }} - {{ dashboard_title }} @@ -118,7 +119,7 @@