♻️ Refactoriza atributos HTML
This commit is contained in:
parent
25d32ec5de
commit
fa32833ffa
19 changed files with 342 additions and 278 deletions
|
|
@ -125,7 +125,7 @@ impl Container {
|
||||||
/// Establece el identificador único (`id`) del contenedor.
|
/// Establece el identificador único (`id`) del contenedor.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
self.id.alter_value(id);
|
self.id.alter_id(id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ impl Dropdown {
|
||||||
/// Establece el identificador único (`id`) del menú desplegable.
|
/// Establece el identificador único (`id`) del menú desplegable.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
self.id.alter_value(id);
|
self.id.alter_id(id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,7 @@ impl Item {
|
||||||
/// Establece el identificador único (`id`) del elemento.
|
/// Establece el identificador único (`id`) del elemento.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
self.id.alter_value(id);
|
self.id.alter_id(id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ pub struct Image {
|
||||||
/// Devuelve el origen de la imagen.
|
/// Devuelve el origen de la imagen.
|
||||||
source: image::Source,
|
source: image::Source,
|
||||||
/// Devuelve el texto alternativo localizado.
|
/// Devuelve el texto alternativo localizado.
|
||||||
alternative: AttrL10n,
|
alternative: Attr<L10n>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for Image {
|
impl Component for Image {
|
||||||
|
|
@ -81,7 +81,7 @@ impl Image {
|
||||||
/// Establece el identificador único (`id`) de la imagen.
|
/// Establece el identificador único (`id`) de la imagen.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
self.id.alter_value(id);
|
self.id.alter_id(id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ impl Nav {
|
||||||
/// Establece el identificador único (`id`) del menú.
|
/// Establece el identificador único (`id`) del menú.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
self.id.alter_value(id);
|
self.id.alter_id(id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@ impl Item {
|
||||||
/// Establece el identificador único (`id`) del elemento.
|
/// Establece el identificador único (`id`) del elemento.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
self.id.alter_value(id);
|
self.id.alter_id(id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ impl Brand {
|
||||||
/// Establece el identificador único (`id`) de la marca.
|
/// Establece el identificador único (`id`) de la marca.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
self.id.alter_value(id);
|
self.id.alter_id(id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ impl Navbar {
|
||||||
/// Establece el identificador único (`id`) de la barra de navegación.
|
/// Establece el identificador único (`id`) de la barra de navegación.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
self.id.alter_value(id);
|
self.id.alter_id(id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ impl Offcanvas {
|
||||||
/// Establece el identificador único (`id`) del panel.
|
/// Establece el identificador único (`id`) del panel.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
self.id.alter_value(id);
|
self.id.alter_id(id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ impl<C: Component> AfterRender<C> {
|
||||||
/// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente
|
/// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente
|
||||||
/// `C` con identificador `id`.
|
/// `C` con identificador `id`.
|
||||||
pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
self.referer_id.alter_value(id);
|
self.referer_id.alter_id(id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ impl<C: Component> BeforeRender<C> {
|
||||||
/// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente
|
/// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente
|
||||||
/// `C` con identificador `id`.
|
/// `C` con identificador `id`.
|
||||||
pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
self.referer_id.alter_value(id);
|
self.referer_id.alter_id(id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ impl Block {
|
||||||
/// Establece el identificador único (`id`) del bloque.
|
/// Establece el identificador único (`id`) del bloque.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
self.id.alter_value(id);
|
self.id.alter_id(id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
13
src/html.rs
13
src/html.rs
|
|
@ -21,17 +21,8 @@ pub use logo::PageTopSvg;
|
||||||
|
|
||||||
// **< HTML ATTRIBUTES >****************************************************************************
|
// **< HTML ATTRIBUTES >****************************************************************************
|
||||||
|
|
||||||
mod attr_id;
|
mod attr;
|
||||||
pub use attr_id::AttrId;
|
pub use attr::{Attr, AttrId, AttrName, AttrValue};
|
||||||
|
|
||||||
mod attr_name;
|
|
||||||
pub use attr_name::AttrName;
|
|
||||||
|
|
||||||
mod attr_value;
|
|
||||||
pub use attr_value::AttrValue;
|
|
||||||
|
|
||||||
mod attr_l10n;
|
|
||||||
pub use attr_l10n::AttrL10n;
|
|
||||||
|
|
||||||
mod attr_classes;
|
mod attr_classes;
|
||||||
pub use attr_classes::{AttrClasses, ClassesOp};
|
pub use attr_classes::{AttrClasses, ClassesOp};
|
||||||
|
|
|
||||||
321
src/html/attr.rs
Normal file
321
src/html/attr.rs
Normal file
|
|
@ -0,0 +1,321 @@
|
||||||
|
use crate::locale::{L10n, LangId};
|
||||||
|
use crate::{builder_fn, AutoDefault};
|
||||||
|
|
||||||
|
/// Valor opcional para atributos HTML.
|
||||||
|
///
|
||||||
|
/// `Attr<T>` encapsula un `Option<T>` y sirve como tipo base para representar atributos HTML
|
||||||
|
/// opcionales, uniformes y tipados.
|
||||||
|
///
|
||||||
|
/// Este tipo **no impone ninguna normalización ni semántica concreta**; dichas reglas se definen en
|
||||||
|
/// implementaciones concretas como `Attr<L10n>` y `Attr<String>`, o en tipos específicos como
|
||||||
|
/// [`AttrId`] y [`AttrName`].
|
||||||
|
#[derive(AutoDefault, Clone, Debug)]
|
||||||
|
pub struct Attr<T>(Option<T>);
|
||||||
|
|
||||||
|
impl<T> Attr<T> {
|
||||||
|
/// Crea un atributo vacío.
|
||||||
|
pub fn empty() -> Self {
|
||||||
|
Self(None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Crea un atributo con valor.
|
||||||
|
pub fn some(value: T) -> Self {
|
||||||
|
Self(Some(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< Attr<T> BUILDER >************************************************************************
|
||||||
|
|
||||||
|
/// Establece un valor para el atributo.
|
||||||
|
#[builder_fn]
|
||||||
|
pub fn with_value(mut self, value: T) -> Self {
|
||||||
|
self.0 = Some(value);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Elimina el valor del atributo.
|
||||||
|
#[builder_fn]
|
||||||
|
pub fn with_none(mut self) -> Self {
|
||||||
|
self.0 = None;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< Attr<T> GETTERS >************************************************************************
|
||||||
|
|
||||||
|
/// Devuelve el valor (clonado), si existe.
|
||||||
|
pub fn get(&self) -> Option<T>
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
self.0.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Devuelve una referencia al valor, si existe.
|
||||||
|
pub fn as_ref(&self) -> Option<&T> {
|
||||||
|
self.0.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Devuelve el valor (propiedad), si existe.
|
||||||
|
pub fn into_inner(self) -> Option<T> {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `true` si no hay valor.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0.is_none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< Attr<L10n> >*********************************************************************************
|
||||||
|
|
||||||
|
/// Extiende [`Attr`] para [texto localizado](crate::locale) en atributos HTML.
|
||||||
|
///
|
||||||
|
/// Encapsula un [`L10n`] para manejar traducciones de forma segura en atributos.
|
||||||
|
///
|
||||||
|
/// # Ejemplo
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use pagetop::prelude::*;
|
||||||
|
/// // Traducción por clave en las locales por defecto de PageTop.
|
||||||
|
/// let hello = Attr::<L10n>::new(L10n::l("test_hello_world"));
|
||||||
|
///
|
||||||
|
/// // Español disponible.
|
||||||
|
/// assert_eq!(
|
||||||
|
/// hello.lookup(&Locale::resolve("es-ES")),
|
||||||
|
/// Some("¡Hola mundo!".to_string())
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// // Japonés no disponible, traduce al idioma de respaldo (`"en-US"`).
|
||||||
|
/// assert_eq!(
|
||||||
|
/// hello.lookup(&Locale::resolve("ja-JP")),
|
||||||
|
/// Some("Hello world!".to_string())
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// // Uso típico en un atributo:
|
||||||
|
/// let title = hello.value(&Locale::resolve("es-ES"));
|
||||||
|
/// // Ejemplo: html! { a title=(title) { "Link" } }
|
||||||
|
/// ```
|
||||||
|
impl Attr<L10n> {
|
||||||
|
/// Crea una nueva instancia `Attr<L10n>`.
|
||||||
|
pub fn new(value: L10n) -> Self {
|
||||||
|
Self::some(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Devuelve la traducción para `language` si puede resolverse.
|
||||||
|
pub fn lookup(&self, language: &impl LangId) -> Option<String> {
|
||||||
|
self.0.as_ref()?.lookup(language)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Devuelve la traducción para `language` o una cadena vacía si no existe.
|
||||||
|
pub fn value(&self, language: &impl LangId) -> String {
|
||||||
|
self.lookup(language).unwrap_or_default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< Attr<String> >*******************************************************************************
|
||||||
|
|
||||||
|
/// Extiende [`Attr`] para cadenas de texto.
|
||||||
|
impl Attr<String> {
|
||||||
|
/// Devuelve el texto como `&str` si existe.
|
||||||
|
pub fn as_str(&self) -> Option<&str> {
|
||||||
|
self.0.as_deref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< AttrId >*************************************************************************************
|
||||||
|
|
||||||
|
/// Identificador normalizado para el atributo `id` o similar de HTML.
|
||||||
|
///
|
||||||
|
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
|
||||||
|
///
|
||||||
|
/// - Se eliminan los espacios al principio y al final.
|
||||||
|
/// - Se convierte a minúsculas.
|
||||||
|
/// - Se sustituyen los espacios (`' '`) intermedios por guiones bajos (`_`).
|
||||||
|
/// - Si el resultado es una cadena vacía, se guarda `None`.
|
||||||
|
///
|
||||||
|
/// # Ejemplo
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use pagetop::prelude::*;
|
||||||
|
/// let id = AttrId::new(" main Section ");
|
||||||
|
/// assert_eq!(id.as_str(), Some("main_section"));
|
||||||
|
///
|
||||||
|
/// let empty = AttrId::default();
|
||||||
|
/// assert_eq!(empty.get(), None);
|
||||||
|
/// ```
|
||||||
|
#[derive(AutoDefault, Clone, Debug)]
|
||||||
|
pub struct AttrId(Attr<String>);
|
||||||
|
|
||||||
|
impl AttrId {
|
||||||
|
/// Crea un nuevo `AttrId` normalizando el valor.
|
||||||
|
pub fn new(id: impl AsRef<str>) -> Self {
|
||||||
|
Self::default().with_id(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< AttrId BUILDER >*************************************************************************
|
||||||
|
|
||||||
|
/// Establece un identificador nuevo normalizando el valor.
|
||||||
|
#[builder_fn]
|
||||||
|
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
|
let id = id.as_ref().trim();
|
||||||
|
if id.is_empty() {
|
||||||
|
self.0 = Attr::default();
|
||||||
|
} else {
|
||||||
|
self.0 = Attr::some(id.to_ascii_lowercase().replace(' ', "_"));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< AttrId GETTERS >*************************************************************************
|
||||||
|
|
||||||
|
/// Devuelve el identificador normalizado, si existe.
|
||||||
|
pub fn get(&self) -> Option<String> {
|
||||||
|
self.0.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Devuelve el identificador normalizado (sin clonar), si existe.
|
||||||
|
pub fn as_str(&self) -> Option<&str> {
|
||||||
|
self.0.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Devuelve el identificador normalizado (propiedad), si existe.
|
||||||
|
pub fn into_inner(self) -> Option<String> {
|
||||||
|
self.0.into_inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `true` si no hay valor.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< AttrName >***********************************************************************************
|
||||||
|
|
||||||
|
/// Nombre normalizado para el atributo `name` o similar de HTML.
|
||||||
|
///
|
||||||
|
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
|
||||||
|
///
|
||||||
|
/// - Se eliminan los espacios al principio y al final.
|
||||||
|
/// - Se convierte a minúsculas.
|
||||||
|
/// - Se sustituyen los espacios (`' '`) intermedios por guiones bajos (`_`).
|
||||||
|
/// - Si el resultado es una cadena vacía, se guarda `None`.
|
||||||
|
///
|
||||||
|
/// # Ejemplo
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use pagetop::prelude::*;
|
||||||
|
/// let name = AttrName::new(" DISplay name ");
|
||||||
|
/// assert_eq!(name.as_str(), Some("display_name"));
|
||||||
|
///
|
||||||
|
/// let empty = AttrName::default();
|
||||||
|
/// assert_eq!(empty.get(), None);
|
||||||
|
/// ```
|
||||||
|
#[derive(AutoDefault, Clone, Debug)]
|
||||||
|
pub struct AttrName(Attr<String>);
|
||||||
|
|
||||||
|
impl AttrName {
|
||||||
|
/// Crea un nuevo `AttrName` normalizando el valor.
|
||||||
|
pub fn new(name: impl AsRef<str>) -> Self {
|
||||||
|
Self::default().with_name(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< AttrName BUILDER >***********************************************************************
|
||||||
|
|
||||||
|
/// Establece un nombre nuevo normalizando el valor.
|
||||||
|
#[builder_fn]
|
||||||
|
pub fn with_name(mut self, name: impl AsRef<str>) -> Self {
|
||||||
|
let name = name.as_ref().trim();
|
||||||
|
if name.is_empty() {
|
||||||
|
self.0 = Attr::default();
|
||||||
|
} else {
|
||||||
|
self.0 = Attr::some(name.to_ascii_lowercase().replace(' ', "_"));
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< AttrName GETTERS >***********************************************************************
|
||||||
|
|
||||||
|
/// Devuelve el nombre normalizado, si existe.
|
||||||
|
pub fn get(&self) -> Option<String> {
|
||||||
|
self.0.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Devuelve el nombre normalizado (sin clonar), si existe.
|
||||||
|
pub fn as_str(&self) -> Option<&str> {
|
||||||
|
self.0.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Devuelve el nombre normalizado (propiedad), si existe.
|
||||||
|
pub fn into_inner(self) -> Option<String> {
|
||||||
|
self.0.into_inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `true` si no hay valor.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< AttrValue >**********************************************************************************
|
||||||
|
|
||||||
|
/// Cadena normalizada para renderizar en atributos HTML.
|
||||||
|
///
|
||||||
|
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
|
||||||
|
///
|
||||||
|
/// - Se eliminan los espacios al principio y al final.
|
||||||
|
/// - Si el resultado es una cadena vacía, se guarda `None`.
|
||||||
|
///
|
||||||
|
/// # Ejemplo
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// # use pagetop::prelude::*;
|
||||||
|
/// let s = AttrValue::new(" a new string ");
|
||||||
|
/// assert_eq!(s.as_str(), Some("a new string"));
|
||||||
|
///
|
||||||
|
/// let empty = AttrValue::default();
|
||||||
|
/// assert_eq!(empty.get(), None);
|
||||||
|
/// ```
|
||||||
|
#[derive(AutoDefault, Clone, Debug)]
|
||||||
|
pub struct AttrValue(Attr<String>);
|
||||||
|
|
||||||
|
impl AttrValue {
|
||||||
|
/// Crea un nuevo `AttrValue` normalizando el valor.
|
||||||
|
pub fn new(value: impl AsRef<str>) -> Self {
|
||||||
|
Self::default().with_str(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< AttrValue BUILDER >**********************************************************************
|
||||||
|
|
||||||
|
/// Establece una cadena nueva normalizando el valor.
|
||||||
|
#[builder_fn]
|
||||||
|
pub fn with_str(mut self, value: impl AsRef<str>) -> Self {
|
||||||
|
let value = value.as_ref().trim();
|
||||||
|
if value.is_empty() {
|
||||||
|
self.0 = Attr::default();
|
||||||
|
} else {
|
||||||
|
self.0 = Attr::some(value.to_string());
|
||||||
|
}
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
// **< AttrValue GETTERS >**********************************************************************
|
||||||
|
|
||||||
|
/// Devuelve la cadena normalizada, si existe.
|
||||||
|
pub fn get(&self) -> Option<String> {
|
||||||
|
self.0.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Devuelve la cadena normalizada (sin clonar), si existe.
|
||||||
|
pub fn as_str(&self) -> Option<&str> {
|
||||||
|
self.0.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Devuelve la cadena normalizada (propiedad), si existe.
|
||||||
|
pub fn into_inner(self) -> Option<String> {
|
||||||
|
self.0.into_inner()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `true` si no hay valor.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0.is_empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
use crate::{builder_fn, AutoDefault};
|
|
||||||
|
|
||||||
/// Identificador normalizado para el atributo `id` o similar de HTML.
|
|
||||||
///
|
|
||||||
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
|
|
||||||
///
|
|
||||||
/// - Se eliminan los espacios al principio y al final.
|
|
||||||
/// - Se convierte a minúsculas.
|
|
||||||
/// - Se sustituyen los espacios intermedios por guiones bajos (`_`).
|
|
||||||
/// - Si el resultado es una cadena vacía, se guarda `None`.
|
|
||||||
///
|
|
||||||
/// # Ejemplo
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use pagetop::prelude::*;
|
|
||||||
/// let id = AttrId::new(" main Section ");
|
|
||||||
/// assert_eq!(id.as_str(), Some("main_section"));
|
|
||||||
///
|
|
||||||
/// let empty = AttrId::default();
|
|
||||||
/// assert_eq!(empty.get(), None);
|
|
||||||
/// ```
|
|
||||||
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
|
|
||||||
pub struct AttrId(Option<String>);
|
|
||||||
|
|
||||||
impl AttrId {
|
|
||||||
/// Crea un nuevo `AttrId` normalizando el valor.
|
|
||||||
pub fn new(value: impl AsRef<str>) -> Self {
|
|
||||||
AttrId::default().with_value(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// **< AttrId BUILDER >*************************************************************************
|
|
||||||
|
|
||||||
/// Establece un identificador nuevo normalizando el valor.
|
|
||||||
#[builder_fn]
|
|
||||||
pub fn with_value(mut self, value: impl AsRef<str>) -> Self {
|
|
||||||
let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_");
|
|
||||||
self.0 = if value.is_empty() { None } else { Some(value) };
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
// **< AttrId GETTERS >*************************************************************************
|
|
||||||
|
|
||||||
/// Devuelve el identificador normalizado, si existe.
|
|
||||||
pub fn get(&self) -> Option<String> {
|
|
||||||
self.0.as_ref().cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Devuelve el identificador normalizado (sin clonar), si existe.
|
|
||||||
pub fn as_str(&self) -> Option<&str> {
|
|
||||||
self.0.as_deref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Devuelve el identificador normalizado (propiedad), si existe.
|
|
||||||
pub fn into_inner(self) -> Option<String> {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `true` si no hay valor.
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.0.is_none()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
use crate::locale::{L10n, LangId};
|
|
||||||
use crate::{builder_fn, AutoDefault};
|
|
||||||
|
|
||||||
/// Texto para [traducir](crate::locale) en atributos HTML.
|
|
||||||
///
|
|
||||||
/// Encapsula un [`L10n`] para manejar traducciones de forma segura en atributos.
|
|
||||||
///
|
|
||||||
/// # Ejemplo
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use pagetop::prelude::*;
|
|
||||||
/// // Traducción por clave en las locales por defecto de PageTop.
|
|
||||||
/// let hello = AttrL10n::new(L10n::l("test_hello_world"));
|
|
||||||
///
|
|
||||||
/// // Español disponible.
|
|
||||||
/// assert_eq!(
|
|
||||||
/// hello.lookup(&Locale::resolve("es-ES")),
|
|
||||||
/// Some("¡Hola mundo!".to_string())
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// // Japonés no disponible, traduce al idioma de respaldo (`"en-US"`).
|
|
||||||
/// assert_eq!(
|
|
||||||
/// hello.lookup(&Locale::resolve("ja-JP")),
|
|
||||||
/// Some("Hello world!".to_string())
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// // Uso típico en un atributo:
|
|
||||||
/// let title = hello.value(&Locale::resolve("es-ES"));
|
|
||||||
/// // Ejemplo: html! { a title=(title) { "Link" } }
|
|
||||||
/// ```
|
|
||||||
#[derive(AutoDefault, Clone, Debug)]
|
|
||||||
pub struct AttrL10n(L10n);
|
|
||||||
|
|
||||||
impl AttrL10n {
|
|
||||||
/// Crea una nueva instancia `AttrL10n`.
|
|
||||||
pub fn new(value: L10n) -> Self {
|
|
||||||
AttrL10n(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// **< AttrL10n BUILDER >***********************************************************************
|
|
||||||
|
|
||||||
/// Establece una traducción nueva.
|
|
||||||
#[builder_fn]
|
|
||||||
pub fn with_value(mut self, value: L10n) -> Self {
|
|
||||||
self.0 = value;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
// **< AttrL10n GETTERS >***********************************************************************
|
|
||||||
|
|
||||||
/// Devuelve la traducción para `language`, si existe.
|
|
||||||
pub fn lookup(&self, language: &impl LangId) -> Option<String> {
|
|
||||||
self.0.lookup(language)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Devuelve la traducción para `language` o una cadena vacía si no existe.
|
|
||||||
pub fn value(&self, language: &impl LangId) -> String {
|
|
||||||
self.0.lookup(language).unwrap_or_default()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
use crate::{builder_fn, AutoDefault};
|
|
||||||
|
|
||||||
/// Nombre normalizado para el atributo `name` o similar de HTML.
|
|
||||||
///
|
|
||||||
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
|
|
||||||
///
|
|
||||||
/// - Se eliminan los espacios al principio y al final.
|
|
||||||
/// - Se convierte a minúsculas.
|
|
||||||
/// - Se sustituyen los espacios intermedios por guiones bajos (`_`).
|
|
||||||
/// - Si el resultado es una cadena vacía, se guarda `None`.
|
|
||||||
///
|
|
||||||
/// # Ejemplo
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use pagetop::prelude::*;
|
|
||||||
/// let name = AttrName::new(" DISplay name ");
|
|
||||||
/// assert_eq!(name.as_str(), Some("display_name"));
|
|
||||||
///
|
|
||||||
/// let empty = AttrName::default();
|
|
||||||
/// assert_eq!(empty.get(), None);
|
|
||||||
/// ```
|
|
||||||
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
|
|
||||||
pub struct AttrName(Option<String>);
|
|
||||||
|
|
||||||
impl AttrName {
|
|
||||||
/// Crea un nuevo `AttrName` normalizando el valor.
|
|
||||||
pub fn new(value: impl AsRef<str>) -> Self {
|
|
||||||
AttrName::default().with_value(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// **< AttrName BUILDER >***********************************************************************
|
|
||||||
|
|
||||||
/// Establece un nombre nuevo normalizando el valor.
|
|
||||||
#[builder_fn]
|
|
||||||
pub fn with_value(mut self, value: impl AsRef<str>) -> Self {
|
|
||||||
let value = value.as_ref().trim().to_ascii_lowercase().replace(' ', "_");
|
|
||||||
self.0 = if value.is_empty() { None } else { Some(value) };
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
// **< AttrName GETTERS >***********************************************************************
|
|
||||||
|
|
||||||
/// Devuelve el nombre normalizado, si existe.
|
|
||||||
pub fn get(&self) -> Option<String> {
|
|
||||||
self.0.as_ref().cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Devuelve el nombre normalizado (sin clonar), si existe.
|
|
||||||
pub fn as_str(&self) -> Option<&str> {
|
|
||||||
self.0.as_deref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Devuelve el nombre normalizado (propiedad), si existe.
|
|
||||||
pub fn into_inner(self) -> Option<String> {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `true` si no hay valor.
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.0.is_none()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
use crate::{builder_fn, AutoDefault};
|
|
||||||
|
|
||||||
/// Cadena normalizada para renderizar en atributos HTML.
|
|
||||||
///
|
|
||||||
/// Este tipo encapsula `Option<String>` garantizando un valor normalizado para su uso:
|
|
||||||
///
|
|
||||||
/// - Se eliminan los espacios al principio y al final.
|
|
||||||
/// - Si el resultado es una cadena vacía, se guarda `None`.
|
|
||||||
///
|
|
||||||
/// # Ejemplo
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use pagetop::prelude::*;
|
|
||||||
/// let s = AttrValue::new(" a new string ");
|
|
||||||
/// assert_eq!(s.as_str(), Some("a new string"));
|
|
||||||
///
|
|
||||||
/// let empty = AttrValue::default();
|
|
||||||
/// assert_eq!(empty.get(), None);
|
|
||||||
/// ```
|
|
||||||
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
|
|
||||||
pub struct AttrValue(Option<String>);
|
|
||||||
|
|
||||||
impl AttrValue {
|
|
||||||
/// Crea un nuevo `AttrValue` normalizando el valor.
|
|
||||||
pub fn new(value: impl AsRef<str>) -> Self {
|
|
||||||
AttrValue::default().with_value(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// **< AttrValue BUILDER >**********************************************************************
|
|
||||||
|
|
||||||
/// Establece una cadena nueva normalizando el valor.
|
|
||||||
#[builder_fn]
|
|
||||||
pub fn with_value(mut self, value: impl AsRef<str>) -> Self {
|
|
||||||
let value = value.as_ref().trim();
|
|
||||||
self.0 = if value.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(value.to_string())
|
|
||||||
};
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
// **< AttrValue GETTERS >**********************************************************************
|
|
||||||
|
|
||||||
/// Devuelve la cadena normalizada, si existe.
|
|
||||||
pub fn get(&self) -> Option<String> {
|
|
||||||
self.0.as_ref().cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Devuelve la cadena normalizada (sin clonar), si existe.
|
|
||||||
pub fn as_str(&self) -> Option<&str> {
|
|
||||||
self.0.as_deref()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Devuelve la cadena normalizada (propiedad), si existe.
|
|
||||||
pub fn into_inner(self) -> Option<String> {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `true` si no hay valor.
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.0.is_none()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -24,8 +24,8 @@ use crate::core::component::{Context, ContextOp, Contextual};
|
||||||
use crate::core::theme::{DefaultRegion, Region, RegionRef, TemplateRef, ThemeRef};
|
use crate::core::theme::{DefaultRegion, Region, RegionRef, TemplateRef, ThemeRef};
|
||||||
use crate::html::{html, Markup, DOCTYPE};
|
use crate::html::{html, Markup, DOCTYPE};
|
||||||
use crate::html::{Assets, Favicon, JavaScript, StyleSheet};
|
use crate::html::{Assets, Favicon, JavaScript, StyleSheet};
|
||||||
|
use crate::html::{Attr, AttrId};
|
||||||
use crate::html::{AttrClasses, ClassesOp};
|
use crate::html::{AttrClasses, ClassesOp};
|
||||||
use crate::html::{AttrId, AttrL10n};
|
|
||||||
use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier};
|
use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier};
|
||||||
use crate::service::HttpRequest;
|
use crate::service::HttpRequest;
|
||||||
use crate::{builder_fn, AutoDefault};
|
use crate::{builder_fn, AutoDefault};
|
||||||
|
|
@ -89,8 +89,8 @@ impl Region for ReservedRegion {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
#[derive(AutoDefault)]
|
#[derive(AutoDefault)]
|
||||||
pub struct Page {
|
pub struct Page {
|
||||||
title : AttrL10n,
|
title : Attr<L10n>,
|
||||||
description : AttrL10n,
|
description : Attr<L10n>,
|
||||||
metadata : Vec<(&'static str, &'static str)>,
|
metadata : Vec<(&'static str, &'static str)>,
|
||||||
properties : Vec<(&'static str, &'static str)>,
|
properties : Vec<(&'static str, &'static str)>,
|
||||||
body_id : AttrId,
|
body_id : AttrId,
|
||||||
|
|
@ -106,8 +106,8 @@ impl Page {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub fn new(request: HttpRequest) -> Self {
|
pub fn new(request: HttpRequest) -> Self {
|
||||||
Page {
|
Page {
|
||||||
title : AttrL10n::default(),
|
title : Attr::<L10n>::default(),
|
||||||
description : AttrL10n::default(),
|
description : Attr::<L10n>::default(),
|
||||||
metadata : Vec::default(),
|
metadata : Vec::default(),
|
||||||
properties : Vec::default(),
|
properties : Vec::default(),
|
||||||
body_id : AttrId::default(),
|
body_id : AttrId::default(),
|
||||||
|
|
@ -149,7 +149,7 @@ impl Page {
|
||||||
/// Establece el atributo `id` del elemento `<body>`.
|
/// Establece el atributo `id` del elemento `<body>`.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_body_id(mut self, id: impl AsRef<str>) -> Self {
|
pub fn with_body_id(mut self, id: impl AsRef<str>) -> Self {
|
||||||
self.body_id.alter_value(id);
|
self.body_id.alter_id(id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue