♻️ (base): El resumen de Pager usa PagerVisibility
Sustituye el bool de `summary` por `PagerVisibility`, con `Auto` como valor por defecto: se activa igual que los botones de navegación y el formulario de salto, sólo cuando el listado se trunca.
This commit is contained in:
parent
ee57d6cacf
commit
825283caa3
2 changed files with 91 additions and 30 deletions
|
|
@ -31,8 +31,7 @@ pub enum PagerAlign {
|
||||||
/// `Pager` permite navegar por las páginas de un listado de ítems cuando supera el número máximo de
|
/// `Pager` permite navegar por las páginas de un listado de ítems cuando supera el número máximo de
|
||||||
/// ítems admitidos por página. Resuelve el enlace para acceder a cada página del listado a partir
|
/// ítems admitidos por página. Resuelve el enlace para acceder a cada página del listado a partir
|
||||||
/// de una ruta base, un conjunto de parámetros de consulta adicionales (orden, búsqueda, etc.) y el
|
/// de una ruta base, un conjunto de parámetros de consulta adicionales (orden, búsqueda, etc.) y el
|
||||||
/// estado actual ([`current_page`](Self::current_page), [`items_per_page`](Self::items_per_page),
|
/// estado actual ([`current_page`], [`items_per_page`], [`total_items`]).
|
||||||
/// [`total_items`](Self::total_items)).
|
|
||||||
///
|
///
|
||||||
/// El componente se renderiza sólo si el listado requiere más de una página.
|
/// El componente se renderiza sólo si el listado requiere más de una página.
|
||||||
///
|
///
|
||||||
|
|
@ -41,33 +40,31 @@ pub enum PagerAlign {
|
||||||
///
|
///
|
||||||
/// El listado de páginas se flanquea con dos botones de navegación: página anterior y página
|
/// El listado de páginas se flanquea con dos botones de navegación: página anterior y página
|
||||||
/// siguiente (las páginas primera y última ya están siempre disponibles como números, así que no
|
/// siguiente (las páginas primera y última ya están siempre disponibles como números, así que no
|
||||||
/// llevan un botón dedicado). Su visibilidad, junto a la del formulario de salto a página, se
|
/// llevan un botón dedicado). Su visibilidad, junto a la del formulario de salto a página y la del
|
||||||
/// controla con [`PagerVisibility`] a través de [`with_prev_next()`](Self::with_prev_next) y
|
/// resumen de páginas, se controla con [`PagerVisibility`] a través de [`with_prev_next()`],
|
||||||
/// [`with_jump()`](Self::with_jump): `Never` los oculta siempre, `Always` los muestra siempre (en
|
/// [`with_jump()`] y [`with_summary()`]: `Never` los oculta siempre, `Always` los muestra siempre,
|
||||||
/// el caso de los botones, con el extremo correspondiente desactivado en vez de oculto), y `Auto`
|
/// y el valor por defecto `Auto` los muestra sólo cuando el paginador necesita truncar el listado
|
||||||
/// -el valor por defecto de ambos- los muestra sólo cuando el número total de páginas supera al
|
/// de páginas por superar el número máximo de páginas visible.
|
||||||
/// número de páginas que se muestra en el paginador; en ese caso, si la página actual coincide con
|
|
||||||
/// un extremo, el botón correspondiente se muestra igualmente, pero desactivado.
|
|
||||||
///
|
///
|
||||||
/// Un elemento `<nav>` envuelve todo el paginador. Lleva un `aria-label` por defecto que puede
|
/// Un elemento `<nav>` envuelve todo el paginador. Lleva un `aria-label` por defecto que puede
|
||||||
/// sustituirse por otro más específico usando [`with_aria_label()`](Self::with_aria_label), por
|
/// sustituirse por otro más específico usando [`with_aria_label()`], por ejemplo cuando una misma
|
||||||
/// ejemplo cuando una misma página tiene varios paginadores.
|
/// página tiene varios paginadores.
|
||||||
///
|
///
|
||||||
/// La alineación horizontal del paginador dentro de este contenedor se controla con [`PagerAlign`]
|
/// La alineación horizontal del paginador dentro de este contenedor se controla con [`PagerAlign`]
|
||||||
/// a través de [`with_align()`](Self::with_align). Por defecto es [`PagerAlign::Center`].
|
/// a través de [`with_align()`]. Por defecto es [`PagerAlign::Center`].
|
||||||
///
|
///
|
||||||
/// # Acotando el número de ítems del paginador
|
/// # Acotando el número de ítems del paginador
|
||||||
///
|
///
|
||||||
/// Con listados largos, mostrar un número por cada página real puede desbordar la interfaz. Con
|
/// Con listados largos, mostrar un número por cada página real puede desbordar la interfaz. Con
|
||||||
/// [`with_window()`](Self::with_window) se puede limitar el número de páginas que se muestran a
|
/// [`with_window()`] se puede limitar el número de páginas que se muestran a cada lado de la página
|
||||||
/// cada lado de la página actual. Por defecto vale `2`, que limita la vista a `9` celdas en total
|
/// actual. Por defecto vale `2`, que limita la vista a `9` celdas en total (sin contar los botones
|
||||||
/// (sin contar los botones de navegación anterior/siguiente). En general, el número máximo de
|
/// de navegación anterior/siguiente). En general, el número máximo de celdas mostradas para un
|
||||||
/// celdas mostradas para un `window` dado es `2 * window + 5`.
|
/// `window` dado es `2 * window + 5`.
|
||||||
///
|
///
|
||||||
/// Si el valor de la ventana es mayor que `0`, `Pager` siempre muestra la primera y la última
|
/// Incluso cuando se trunca el paginador, `Pager` siempre muestra la primera y la última página
|
||||||
/// página como números, más la ventana indicada antes y después de la página actual, sustituyendo
|
/// como números, más la ventana indicada antes y después de la página actual, sustituyendo por una
|
||||||
/// por una elipsis (`…`) cualquier tramo oculto de dos o más páginas. Si el tramo oculto es de una
|
/// elipsis (`…`) cualquier tramo oculto de dos o más páginas. Si el tramo oculto es de una sola
|
||||||
/// sola página, se muestra directamente en vez de la elipsis, porque ocultarla no ahorra espacio.
|
/// página, se muestra directamente en vez de la elipsis, porque ocultarla no ahorra espacio.
|
||||||
///
|
///
|
||||||
/// Por ejemplo, con `with_window(3)`, página actual `34` y con `200` páginas en total, el paginador
|
/// Por ejemplo, con `with_window(3)`, página actual `34` y con `200` páginas en total, el paginador
|
||||||
/// se mostraría así:
|
/// se mostraría así:
|
||||||
|
|
@ -83,8 +80,8 @@ pub enum PagerAlign {
|
||||||
/// para saltar directamente a una página escribiendo su número, sin depender de JavaScript. Un
|
/// para saltar directamente a una página escribiendo su número, sin depender de JavaScript. Un
|
||||||
/// único campo numérico (`min`/`max` según el total de páginas) y un botón de envío.
|
/// único campo numérico (`min`/`max` según el total de páginas) y un botón de envío.
|
||||||
///
|
///
|
||||||
/// Con [`with_summary()`](Self::with_summary) se puede añadir un texto que resume la vista de las
|
/// Con [`with_summary()`] se puede añadir un texto que resume la vista de las páginas que se
|
||||||
/// páginas que se muestran en ese momento. Por defecto está oculto.
|
/// muestran en ese momento (ver más arriba su visibilidad según [`PagerVisibility`]).
|
||||||
///
|
///
|
||||||
/// # Clases CSS
|
/// # Clases CSS
|
||||||
///
|
///
|
||||||
|
|
@ -122,6 +119,16 @@ pub enum PagerAlign {
|
||||||
/// .with_items_per_page(20)
|
/// .with_items_per_page(20)
|
||||||
/// .with_total_items(97);
|
/// .with_total_items(97);
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`current_page`]: Self::current_page
|
||||||
|
/// [`items_per_page`]: Self::items_per_page
|
||||||
|
/// [`total_items`]: Self::total_items
|
||||||
|
/// [`with_window()`]: Self::with_window
|
||||||
|
/// [`with_align()`]: Self::with_align
|
||||||
|
/// [`with_summary()`]: Self::with_summary
|
||||||
|
/// [`with_prev_next()`]: Self::with_prev_next
|
||||||
|
/// [`with_jump()`]: Self::with_jump
|
||||||
|
/// [`with_aria_label()`]: Self::with_aria_label
|
||||||
#[derive(AutoDefault, Clone, Debug, Getters)]
|
#[derive(AutoDefault, Clone, Debug, Getters)]
|
||||||
pub struct Pager {
|
pub struct Pager {
|
||||||
/// Devuelve identificador, clases CSS, atributos HTML y valores extra del componente.
|
/// Devuelve identificador, clases CSS, atributos HTML y valores extra del componente.
|
||||||
|
|
@ -146,8 +153,8 @@ pub struct Pager {
|
||||||
window: u64,
|
window: u64,
|
||||||
/// Devuelve la alineación horizontal del paginador dentro de su contenedor.
|
/// Devuelve la alineación horizontal del paginador dentro de su contenedor.
|
||||||
align: PagerAlign,
|
align: PagerAlign,
|
||||||
/// Devuelve si se muestra el resumen ("Showing 1-20 of 97") antes del listado de páginas.
|
/// Devuelve la visibilidad del resumen de las páginas que se muestran en cada vista.
|
||||||
summary: bool,
|
summary: PagerVisibility,
|
||||||
/// Devuelve la visibilidad de los botones de página anterior/siguiente.
|
/// Devuelve la visibilidad de los botones de página anterior/siguiente.
|
||||||
prev_next: PagerVisibility,
|
prev_next: PagerVisibility,
|
||||||
/// Devuelve la visibilidad del formulario para saltar directamente a una página.
|
/// Devuelve la visibilidad del formulario para saltar directamente a una página.
|
||||||
|
|
@ -218,10 +225,15 @@ impl Component for Pager {
|
||||||
PagerVisibility::Always => true,
|
PagerVisibility::Always => true,
|
||||||
PagerVisibility::Auto => truncated,
|
PagerVisibility::Auto => truncated,
|
||||||
};
|
};
|
||||||
|
let show_summary = match self.summary() {
|
||||||
|
PagerVisibility::Never => false,
|
||||||
|
PagerVisibility::Always => true,
|
||||||
|
PagerVisibility::Auto => truncated,
|
||||||
|
};
|
||||||
|
|
||||||
Ok(html! {
|
Ok(html! {
|
||||||
nav (self.props()) aria-label=(self.aria_label().using(cx)) {
|
nav (self.props()) aria-label=(self.aria_label().using(cx)) {
|
||||||
@if *self.summary() {
|
@if show_summary {
|
||||||
@let items_per_page = self.items_per_page().max(1);
|
@let items_per_page = self.items_per_page().max(1);
|
||||||
@let first = (page - 1) * items_per_page + 1;
|
@let first = (page - 1) * items_per_page + 1;
|
||||||
@let last = (page * items_per_page).min(self.total_items());
|
@let last = (page * items_per_page).min(self.total_items());
|
||||||
|
|
@ -393,9 +405,15 @@ impl Pager {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Establece si se muestra el resumen de las páginas que se muestran en ese momento.
|
/// Establece la visibilidad del resumen de las páginas que se muestran en cada vista. Por
|
||||||
|
/// defecto es `PagerVisibility::Auto`: sólo se muestra cuando el número total de páginas supera
|
||||||
|
/// al número de páginas que se muestra en el paginador, igual que [`with_prev_next()`] y
|
||||||
|
/// [`with_jump()`].
|
||||||
|
///
|
||||||
|
/// [`with_prev_next()`]: Self::with_prev_next
|
||||||
|
/// [`with_jump()`]: Self::with_jump
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_summary(mut self, summary: bool) -> Self {
|
pub fn with_summary(mut self, summary: PagerVisibility) -> Self {
|
||||||
self.summary = summary;
|
self.summary = summary;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,9 @@ async fn with_aria_label_overrides_the_default() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pagetop::test]
|
#[pagetop::test]
|
||||||
async fn summary_is_hidden_by_default() {
|
async fn summary_is_hidden_by_default_when_not_truncated() {
|
||||||
|
// 97 items at 20 per page is only 5 pages: with the default window (2) that fits without
|
||||||
|
// truncation, so `PagerVisibility::Auto` keeps the summary hidden.
|
||||||
let mut pager = Pager::new()
|
let mut pager = Pager::new()
|
||||||
.with_base_path("/list")
|
.with_base_path("/list")
|
||||||
.with_current_page(1)
|
.with_current_page(1)
|
||||||
|
|
@ -53,6 +55,19 @@ async fn summary_is_hidden_by_default() {
|
||||||
assert!(!html.contains("pager-summary"));
|
assert!(!html.contains("pager-summary"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[pagetop::test]
|
||||||
|
async fn summary_is_shown_by_default_when_truncated() {
|
||||||
|
let mut pager = Pager::new()
|
||||||
|
.with_base_path("/list")
|
||||||
|
.with_current_page(10)
|
||||||
|
.with_items_per_page(1)
|
||||||
|
.with_total_items(20);
|
||||||
|
|
||||||
|
let html = pager.render(&mut Context::default()).await.into_string();
|
||||||
|
|
||||||
|
assert!(html.contains("pager-summary"));
|
||||||
|
}
|
||||||
|
|
||||||
#[pagetop::test]
|
#[pagetop::test]
|
||||||
async fn summary_shows_the_range_of_the_current_page() {
|
async fn summary_shows_the_range_of_the_current_page() {
|
||||||
let mut first_page = Pager::new()
|
let mut first_page = Pager::new()
|
||||||
|
|
@ -60,7 +75,7 @@ async fn summary_shows_the_range_of_the_current_page() {
|
||||||
.with_current_page(1)
|
.with_current_page(1)
|
||||||
.with_items_per_page(20)
|
.with_items_per_page(20)
|
||||||
.with_total_items(97)
|
.with_total_items(97)
|
||||||
.with_summary(true);
|
.with_summary(PagerVisibility::Always);
|
||||||
let html = first_page
|
let html = first_page
|
||||||
.render(&mut Context::default())
|
.render(&mut Context::default())
|
||||||
.await
|
.await
|
||||||
|
|
@ -73,7 +88,7 @@ async fn summary_shows_the_range_of_the_current_page() {
|
||||||
.with_current_page(5)
|
.with_current_page(5)
|
||||||
.with_items_per_page(20)
|
.with_items_per_page(20)
|
||||||
.with_total_items(97)
|
.with_total_items(97)
|
||||||
.with_summary(true);
|
.with_summary(PagerVisibility::Always);
|
||||||
let html = last_page
|
let html = last_page
|
||||||
.render(&mut Context::default())
|
.render(&mut Context::default())
|
||||||
.await
|
.await
|
||||||
|
|
@ -81,6 +96,34 @@ async fn summary_shows_the_range_of_the_current_page() {
|
||||||
assert!(html.contains(r#"<span class="pager-summary">Showing 81-97 of 97</span>"#));
|
assert!(html.contains(r#"<span class="pager-summary">Showing 81-97 of 97</span>"#));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[pagetop::test]
|
||||||
|
async fn summary_can_be_forced_to_always_show_even_when_not_truncated() {
|
||||||
|
let mut pager = Pager::new()
|
||||||
|
.with_base_path("/list")
|
||||||
|
.with_current_page(1)
|
||||||
|
.with_items_per_page(20)
|
||||||
|
.with_total_items(97)
|
||||||
|
.with_summary(PagerVisibility::Always);
|
||||||
|
|
||||||
|
let html = pager.render(&mut Context::default()).await.into_string();
|
||||||
|
|
||||||
|
assert!(html.contains("pager-summary"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pagetop::test]
|
||||||
|
async fn summary_never_shows_it_even_when_truncated() {
|
||||||
|
let mut pager = Pager::new()
|
||||||
|
.with_base_path("/list")
|
||||||
|
.with_current_page(10)
|
||||||
|
.with_items_per_page(1)
|
||||||
|
.with_total_items(20)
|
||||||
|
.with_summary(PagerVisibility::Never);
|
||||||
|
|
||||||
|
let html = pager.render(&mut Context::default()).await.into_string();
|
||||||
|
|
||||||
|
assert!(!html.contains("pager-summary"));
|
||||||
|
}
|
||||||
|
|
||||||
#[pagetop::test]
|
#[pagetop::test]
|
||||||
async fn renders_page_links_and_current_page() {
|
async fn renders_page_links_and_current_page() {
|
||||||
let mut pager = Pager::new()
|
let mut pager = Pager::new()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue