예제 #1
0
def get_column_controls(
    url: URL,
    columns: typing.Dict[str, str],
    selected_column: typing.Optional[str],
    is_reverse: bool,
) -> typing.List[ColumnControl]:
    controls = []
    for column_id, name in columns.items():

        if selected_column != column_id:
            # Column is not selected. Link URL to forward search.
            linked_url = url.include_query_params(
                order=column_id).remove_query_params("page")
        elif not is_reverse:
            # Column is selected as a forward search. Link URL to reverse search.
            linked_url = url.include_query_params(
                order="-" + column_id).remove_query_params("page")
        else:
            # Column is selected as a reverse search. Link URL to remove search.
            linked_url = url.remove_query_params("order").remove_query_params(
                "page")

        control = ColumnControl(
            id=column_id,
            text=name,
            url=linked_url,
            is_forward_sorted=selected_column == column_id and not is_reverse,
            is_reverse_sorted=selected_column == column_id and is_reverse,
        )
        controls.append(control)
    return controls
예제 #2
0
def test_url_query_params():
    u = URL("https://example.org/path/?page=3")
    assert u.query == "page=3"
    u = u.include_query_params(page=4)
    assert str(u) == "https://example.org/path/?page=4"
    u = u.include_query_params(search="testing")
    assert str(u) == "https://example.org/path/?page=4&search=testing"
    u = u.replace_query_params(order="name")
    assert str(u) == "https://example.org/path/?order=name"
    u = u.remove_query_params("order")
    assert str(u) == "https://example.org/path/"
예제 #3
0
def get_page_controls(url: URL, current_page: int,
                      total_pages: int) -> typing.List[PageControl]:
    """
    Returns a list of pagination controls, using GitHub's style for rendering
    which controls should be displayed. See eg. issue pages in GitHub.

    Previous [1] 2 3 4 5 ... 14 15 Next
    """
    assert total_pages >= 1
    assert current_page >= 1
    assert current_page <= total_pages

    # If we've only got a single page, then don't include pagination controls.
    if total_pages == 1:
        return []

    # We always have 5 contextual page numbers around the current page.
    if current_page <= 2:
        # If we're on the first or second-to-first page, then our 5 contextual
        # pages should start from the first page onwards.
        main_block = inclusive_range(1, 5, cutoff=total_pages)
    elif current_page >= total_pages - 1:
        # If we're on the last or second-to-last page, then our 5 contextual
        # pages should end with the final page backwards.
        main_block = inclusive_range(total_pages - 4,
                                     total_pages,
                                     cutoff=total_pages)
    else:
        # All other cases, our 5 contextual pages should be 2 pages on either
        # side of our current page.
        main_block = inclusive_range(current_page - 2,
                                     current_page + 2,
                                     cutoff=total_pages)

    # We always have 2 contextual page numbers at the start.
    start_block = inclusive_range(1, 2, cutoff=total_pages)
    if main_block[0] == 4:
        #  If we've only got a gap of one between the start and main blocks
        # then fill in the gap with a page marker.
        # | 1 2 3 4 5 [6] 7 8
        start_block += [3]
    elif main_block[0] > 4:
        # If we've got a gap of more that one between the start and main
        # blocks then fill in the gap with an ellipsis marker.
        # | 1 2 … 5 6 [7] 8 9
        start_block += [None]

    # We always have 2 contextual page numbers at the end.
    end_block = inclusive_range(total_pages - 1,
                                total_pages,
                                cutoff=total_pages)
    if main_block[-1] == total_pages - 3:
        # If we've got a gap of one between the end and main blocks then
        # fill in the gap with an page marker.
        # 92 93 [94] 95 96 97 98 99 |
        end_block = [total_pages - 2] + end_block
    elif main_block[-1] < total_pages - 3:
        # If we've got a gap of more that one between the end and main
        # blocks then fill in the gap with an ellipsis marker.
        # 91 92 [93] 94 95 … 98 99 |
        end_block = [None] + end_block

    # We've got a list of integer/None values representing which pages to
    # display in the controls. Now we use those to generate the actual
    # PageControl instances.
    seen_numbers = set()
    controls = []

    # Add a 'Previous' page control.
    if current_page == 1:
        previous_url = None
        previous_disabled = True
    elif current_page == 2:
        previous_url = url.remove_query_params("page")
        previous_disabled = False
    else:
        previous_url = url.include_query_params(page=current_page - 1)
        previous_disabled = False

    previous = PageControl(text="Previous",
                           url=previous_url,
                           is_disabled=previous_disabled)
    controls.append(previous)

    for page_number in start_block + main_block + end_block:
        if page_number is None:
            gap = PageControl(text="…", is_disabled=True)
            controls.append(gap)
        elif page_number not in seen_numbers:
            seen_numbers.add(page_number)
            if page_number == 1:
                page_url = url.remove_query_params("page")
            else:
                page_url = url.include_query_params(page=page_number)
            page = PageControl(
                text=str(page_number),
                url=page_url,
                is_active=page_number == current_page,
            )
            controls.append(page)

    # Add a 'Next' page control.
    if current_page == total_pages:
        next_url = None
        next_disabled = True
    else:
        next_url = url.include_query_params(page=current_page + 1)
        next_disabled = False

    next = PageControl(text="Next", url=next_url, is_disabled=next_disabled)
    controls.append(next)

    return controls