Commit b356bf09 authored by Eduardo Silva's avatar Eduardo Silva
Browse files

finalizacao do componente de tabela com pagination funcionando

parent 2c654ac2
...@@ -347,52 +347,234 @@ class BRTableFooterNode(template.Node): ...@@ -347,52 +347,234 @@ class BRTableFooterNode(template.Node):
# O conteúdo interno é HTML de template, marcado como seguro. # O conteúdo interno é HTML de template, marcado como seguro.
return format_html('<div class="table-footer">{}</div>', mark_safe(self.nodelist.render(context))) return format_html('<div class="table-footer">{}</div>', mark_safe(self.nodelist.render(context)))
# -----------------------------------------------------------------------------
# Funções utilitárias necessárias para a paginação DSGov (versão tabela)
# -----------------------------------------------------------------------------
def build_page_url(request, page, extra_params=""):
"""Monta a URL com o número da página e preserva outros parâmetros GET."""
params = request.GET.copy()
# Atualiza ou adiciona o parâmetro 'page'
params["page"] = page
querystring = params.urlencode()
# 🔹 Remove 'page' e 'per_page' duplicados de extra_params
if extra_params:
cleaned_extra = "&".join(
[
p
for p in extra_params.split("&")
if not (p.startswith("page=") or p.startswith("per_page="))
]
)
if cleaned_extra:
querystring += f"&{cleaned_extra}"
return f"?{querystring}"
def build_per_page_url(request, per_page, extra_params=""):
"""Monta a URL com o número de itens por página e reseta para a primeira página."""
params = request.GET.copy()
# Remove o per_page anterior para não duplicar
if "per_page" in params:
del params["per_page"]
params["per_page"] = per_page
querystring = params.urlencode()
# Remove 'page' e 'per_page' duplicados de extra_params
if extra_params:
cleaned_extra = "&".join(
[
p
for p in extra_params.split("&")
if not (p.startswith("page=") or p.startswith("per_page="))
]
)
if cleaned_extra:
querystring += f"&{cleaned_extra}"
return f"?{querystring}"
@register.simple_tag(takes_context=True) @register.simple_tag(takes_context=True)
def br_table_pagination(context): def br_table_pagination(context, page_obj=None, extra_params="", per_page_options=None):
"""Renderiza o componente de paginação da tabela.""" """
meta = context.get('br_table_meta', {}) Renderiza paginação DSGov (versão tabela).
total = meta.get('data_total', 0)
current = meta.get('data_current', 1) Exemplo de uso no template:
per_page = meta.get('data_per_page', 10) {% br_table_pagination page_obj=page_obj extra_params=extra_params %}
- page_obj: objeto do Django Paginator (ex: `page_obj` vindo da view)
- extra_params: string adicional de parâmetros (opcional)
- per_page_options: lista de opções de "itens por página" (ex: 10,20,30,50,100 etc)
"""
request = context["request"]
if not page_obj:
# Renderiza a versão genérica/placeholder
return format_html(
"""
<nav class="br-pagination" aria-label="paginação" data-total="50" data-current="1" data-per-page="20">
<div class="pagination-per-page">
<div class="br-select">
<div class="br-input">
<label for="per-page-selection">Exibir</label>
<input id="per-page-selection" type="text" placeholder=" " value="20"/>
<button class="br-button" type="button" aria-label="Exibir lista" tabindex="-1" data-trigger="data-trigger"><i class="fas fa-angle-down" aria-hidden="true"></i>
</button>
</div>
<div class="br-list" tabindex="0">
<div class="br-item" tabindex="-1">
<div class="br-radio">
<input id="per-page-10" type="radio" name="per-page" value="10"/>
<label for="per-page-10">10</label>
</div>
</div>
<div class="br-item" tabindex="-1">
<div class="br-radio">
<input id="per-page-20" type="radio" name="per-page" value="20" checked="checked"/>
<label for="per-page-20">20</label>
</div>
</div>
<div class="br-item" tabindex="-1">
<div class="br-radio">
<input id="per-page-30" type="radio" name="per-page" value="30"/>
<label for="per-page-30">30</label>
</div>
</div>
</div>
</div>
</div><span class="br-divider d-none d-sm-block mx-3"></span>
<div class="pagination-information d-none d-sm-flex"><span class="current">1</span>&ndash;<span class="per-page">20</span>&nbsp;de&nbsp;<span class="total">50</span>&nbsp;itens</div>
<div class="pagination-go-to-page d-none d-sm-flex ml-auto">
<div class="br-select">
<div class="br-input">
<label for="go-to-selection">Página</label>
<input id="go-to-selection" type="text" placeholder=" " value="1"/>
<button class="br-button" type="button" aria-label="Exibir lista" tabindex="-1" data-trigger="data-trigger"><i class="fas fa-angle-down" aria-hidden="true"></i>
</button>
</div>
<div class="br-list" tabindex="0">
<div class="br-item" tabindex="-1">
<div class="br-radio">
<input id="go-to-1" type="radio" name="go-to" value="1" checked="checked"/>
<label for="go-to-1">1</label>
</div>
</div>
<div class="br-item" tabindex="-1">
<div class="br-radio">
<input id="go-to-2" type="radio" name="go-to" value="2"/>
<label for="go-to-2">2</label>
</div>
</div>
<div class="br-item" tabindex="-1">
<div class="br-radio">
<input id="go-to-3" type="radio" name="go-to" value="3"/>
<label for="go-to-3">3</label>
</div>
</div>
</div>
</div>
</div><span class="br-divider d-none d-sm-block mx-3"></span>
<div class="pagination-arrows ml-auto ml-sm-0">
<button class="br-button circle disabled" type="button" aria-label="Voltar página"><i class="fas fa-angle-left" aria-hidden="true"></i>
</button>
<button class="br-button circle" type="button" aria-label="Página seguinte"><i class="fas fa-angle-right" aria-hidden="true"></i>
</button>
</div>
</nav>
"""
)
# Dados base
current_page = page_obj.number
total_items = page_obj.paginator.count
per_page = page_obj.paginator.per_page
total_pages = page_obj.paginator.num_pages
per_page_options = per_page_options or [10, 20, 30]
per_page_id = meta.get('per_page_select_id', _uniq_id('per-page-selection')) # Cálculo da exibição “X–Y de Z itens”
go_to_id = meta.get('go_to_select_id', _uniq_id('go-to-selection')) start_item = (current_page - 1) * per_page + 1
end_item = min(start_item + per_page - 1, total_items)
per_page_options = [10, 20, 30] # Botões prev/next
prev_disabled = "disabled" if not page_obj.has_previous() else ""
next_disabled = "disabled" if not page_obj.has_next() else ""
prev_link = (
build_page_url(request, page_obj.previous_page_number(), extra_params)
if page_obj.has_previous()
else "javascript:void(0)"
)
next_link = (
build_page_url(request, page_obj.next_page_number(), extra_params)
if page_obj.has_next()
else "javascript:void(0)"
)
# Select de “itens por página”
per_page_html = [] per_page_html = []
for opt in per_page_options: for opt in per_page_options:
checked = 'checked' if opt == per_page else '' checked = "checked" if opt == per_page else ""
radio_id = f'{per_page_id}-{opt}' # Adicionar a URL de navegação ao clicar no rádio
per_page_html.append(format_html( url = build_per_page_url(request, opt, extra_params)
'<div class="br-item" tabindex="-1"><div class="br-radio">' per_page_html.append(
'<input id="{id}" type="radio" name="{name}" value="{val}" {checked}/>' format_html(
'<label for="{id}">{label}</label>' """
'</div></div>', <div class="br-item" tabindex="-1">
id=radio_id, name=format_html('per-page-{}', per_page_id), val=str(opt), checked=mark_safe(checked), label=str(opt) <div class="br-radio">
)) <input id="per-page-{0}" type="radio" name="per-page" value="{0}" {1}
onclick="window.location.href='{2}'"/>
# number of pages <label for="per-page-{0}">{0}</label>
pages = max(1, (total + per_page - 1) // per_page) </div>
</div>
""",
opt,
mark_safe(checked),
mark_safe(url),
)
)
# Select de “ir para página”
go_to_html = [] go_to_html = []
for p in range(1, pages + 1): for p in range(1, total_pages + 1):
checked = 'checked' if p == current else '' checked = "checked" if p == current_page else ""
radio_id = f'{go_to_id}-{p}' # Adicionar a URL de navegação ao clicar no rádio
go_to_html.append(format_html( url = build_page_url(request, p, extra_params)
'<div class="br-item" tabindex="-1"><div class="br-radio">' go_to_html.append(
'<input id="{id}" type="radio" name="{name}" value="{val}" {checked}/>' format_html(
'<label for="{id}">{label}</label>' """
'</div></div>', <div class="br-item" tabindex="-1">
id=radio_id, name=format_html('go-to-{}', go_to_id), val=str(p), checked=mark_safe(checked), label=str(p) <div class="br-radio">
)) <input id="go-to-{0}" type="radio" name="go-to" value="{0}" {1}
onclick="window.location.href='{2}'"/>
# pagination html assembled <label for="go-to-{0}">{0}</label>
return format_html(''' </div>
<nav class="br-pagination" aria-label="paginação" data-total="{total}" data-current="{current}" data-per-page="{per_page}"> </div>
""",
p,
mark_safe(checked),
mark_safe(url),
)
)
# HTML final
return format_html(
"""
<nav class="br-pagination" aria-label="paginação"
data-total="{total}" data-current="{current}" data-per-page="{per_page}">
<div class="pagination-per-page"> <div class="pagination-per-page">
<div class="br-select"> <div class="br-select">
<div class="br-input"> <div class="br-input">
<label for="{per_page_id}">Exibir</label> <label for="per-page-selection">Exibir</label>
<input id="{per_page_id}" type="text" placeholder=" "/> <input id="per-page-selection" type="text" placeholder=" " value="{per_page}">
<button class="br-button" type="button" aria-label="Exibir lista" tabindex="-1" data-trigger="data-trigger"> <button class="br-button" type="button" aria-label="Exibir lista" tabindex="-1" data-trigger="data-trigger">
<i class="fas fa-angle-down" aria-hidden="true"></i> <i class="fas fa-angle-down" aria-hidden="true"></i>
</button> </button>
...@@ -404,15 +586,15 @@ def br_table_pagination(context): ...@@ -404,15 +586,15 @@ def br_table_pagination(context):
</div> </div>
<span class="br-divider d-none d-sm-block mx-3"></span> <span class="br-divider d-none d-sm-block mx-3"></span>
<div class="pagination-information d-none d-sm-flex"> <div class="pagination-information d-none d-sm-flex">
<span class="current">{current}</span>&ndash; <span class="current">{start}</span>&ndash;
<span class="per-page">{per_page}</span>&nbsp;de&nbsp; <span class="per-page">{end}</span>&nbsp;de&nbsp;
<span class="total">{total}</span>&nbsp;itens <span class="total">{total}</span>&nbsp;itens
</div> </div>
<div class="pagination-go-to-page d-none d-sm-flex ml-auto"> <div class="pagination-go-to-page d-none d-sm-flex ml-auto">
<div class="br-select"> <div class="br-select">
<div class="br-input"> <div class="br-input">
<label for="{go_to_id}">Página</label> <label for="go-to-selection">Página</label>
<input id="{go_to_id}" type="text" placeholder=" "/> <input id="go-to-selection" type="text" placeholder=" " value="{current}">
<button class="br-button" type="button" aria-label="Exibir lista" tabindex="-1" data-trigger="data-trigger"> <button class="br-button" type="button" aria-label="Exibir lista" tabindex="-1" data-trigger="data-trigger">
<i class="fas fa-angle-down" aria-hidden="true"></i> <i class="fas fa-angle-down" aria-hidden="true"></i>
</button> </button>
...@@ -424,20 +606,24 @@ def br_table_pagination(context): ...@@ -424,20 +606,24 @@ def br_table_pagination(context):
</div> </div>
<span class="br-divider d-none d-sm-block mx-3"></span> <span class="br-divider d-none d-sm-block mx-3"></span>
<div class="pagination-arrows ml-auto ml-sm-0"> <div class="pagination-arrows ml-auto ml-sm-0">
<button class="br-button circle" type="button" aria-label="Voltar página"> <a href="{prev_link}" class="br-button circle {prev_disabled}" type="button" aria-label="Voltar página">
<i class="fas fa-angle-left" aria-hidden="true"></i> <i class="fas fa-angle-left" aria-hidden="true"></i>
</button> </a>
<button class="br-button circle" type="button" aria-label="Página seguinte"> <a href="{next_link}" class="br-button circle {next_disabled}" type="button" aria-label="Página seguinte">
<i class="fas fa-angle-right" aria-hidden="true"></i> <i class="fas fa-angle-right" aria-hidden="true"></i>
</button> </a>
</div> </div>
</nav> </nav>
''', """,
total=total, total=total_items,
current=current, current=current_page,
per_page=per_page, per_page=per_page,
per_page_id=per_page_id, start=start_item,
go_to_id=go_to_id, end=end_item,
per_page_html=mark_safe(''.join(per_page_html)), per_page_html=mark_safe("".join(per_page_html)),
go_to_html=mark_safe(''.join(go_to_html)) go_to_html=mark_safe("".join(go_to_html)),
prev_link=prev_link,
next_link=next_link,
prev_disabled=prev_disabled,
next_disabled=next_disabled,
) )
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
{% block content %} {% block content %}
{% br_table data-search="data-search" data-total="50" data-current="1" data-per-page="20" %} {% br_table data-search="data-search" %}
{% br_table_header %} {% br_table_header %}
{% br_table_title %}Tabela irregular 2{% end_br_table_title %} {% br_table_title %}Tabela irregular 2{% end_br_table_title %}
{% br_table_actions_trigger %} {% br_table_actions_trigger %}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment