From fa32833ffa5f74d1651208addc1187564c449891 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Sun, 28 Dec 2025 14:03:35 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactoriza=20atributos=20?= =?UTF-8?q?HTML?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/theme/container/component.rs | 2 +- .../src/theme/dropdown/component.rs | 2 +- .../src/theme/dropdown/item.rs | 2 +- .../src/theme/image/component.rs | 4 +- .../src/theme/nav/component.rs | 2 +- .../pagetop-bootsier/src/theme/nav/item.rs | 2 +- .../src/theme/navbar/brand.rs | 2 +- .../src/theme/navbar/component.rs | 2 +- .../src/theme/offcanvas/component.rs | 2 +- .../component/after_render_component.rs | 2 +- .../component/before_render_component.rs | 2 +- src/base/component/block.rs | 2 +- src/html.rs | 13 +- src/html/attr.rs | 321 ++++++++++++++++++ src/html/attr_id.rs | 62 ---- src/html/attr_l10n.rs | 60 ---- src/html/attr_name.rs | 62 ---- src/html/attr_value.rs | 64 ---- src/response/page.rs | 12 +- 19 files changed, 342 insertions(+), 278 deletions(-) create mode 100644 src/html/attr.rs delete mode 100644 src/html/attr_id.rs delete mode 100644 src/html/attr_l10n.rs delete mode 100644 src/html/attr_name.rs delete mode 100644 src/html/attr_value.rs diff --git a/extensions/pagetop-bootsier/src/theme/container/component.rs b/extensions/pagetop-bootsier/src/theme/container/component.rs index 56868fb5..0cebdef5 100644 --- a/extensions/pagetop-bootsier/src/theme/container/component.rs +++ b/extensions/pagetop-bootsier/src/theme/container/component.rs @@ -125,7 +125,7 @@ impl Container { /// Establece el identificador único (`id`) del contenedor. #[builder_fn] pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); + self.id.alter_id(id); self } diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs index ffc754ed..45e446e7 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs @@ -166,7 +166,7 @@ impl Dropdown { /// Establece el identificador único (`id`) del menú desplegable. #[builder_fn] pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); + self.id.alter_id(id); self } diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/item.rs b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs index fc7f52cb..cedcccb4 100644 --- a/extensions/pagetop-bootsier/src/theme/dropdown/item.rs +++ b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs @@ -263,7 +263,7 @@ impl Item { /// Establece el identificador único (`id`) del elemento. #[builder_fn] pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); + self.id.alter_id(id); self } diff --git a/extensions/pagetop-bootsier/src/theme/image/component.rs b/extensions/pagetop-bootsier/src/theme/image/component.rs index 88d5ee29..84d669d6 100644 --- a/extensions/pagetop-bootsier/src/theme/image/component.rs +++ b/extensions/pagetop-bootsier/src/theme/image/component.rs @@ -20,7 +20,7 @@ pub struct Image { /// Devuelve el origen de la imagen. source: image::Source, /// Devuelve el texto alternativo localizado. - alternative: AttrL10n, + alternative: Attr, } impl Component for Image { @@ -81,7 +81,7 @@ impl Image { /// Establece el identificador único (`id`) de la imagen. #[builder_fn] pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); + self.id.alter_id(id); self } diff --git a/extensions/pagetop-bootsier/src/theme/nav/component.rs b/extensions/pagetop-bootsier/src/theme/nav/component.rs index 39acff53..283d3d27 100644 --- a/extensions/pagetop-bootsier/src/theme/nav/component.rs +++ b/extensions/pagetop-bootsier/src/theme/nav/component.rs @@ -77,7 +77,7 @@ impl Nav { /// Establece el identificador único (`id`) del menú. #[builder_fn] pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); + self.id.alter_id(id); self } diff --git a/extensions/pagetop-bootsier/src/theme/nav/item.rs b/extensions/pagetop-bootsier/src/theme/nav/item.rs index 36ca8365..3189f28d 100644 --- a/extensions/pagetop-bootsier/src/theme/nav/item.rs +++ b/extensions/pagetop-bootsier/src/theme/nav/item.rs @@ -286,7 +286,7 @@ impl Item { /// Establece el identificador único (`id`) del elemento. #[builder_fn] pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); + self.id.alter_id(id); self } diff --git a/extensions/pagetop-bootsier/src/theme/navbar/brand.rs b/extensions/pagetop-bootsier/src/theme/navbar/brand.rs index 744aa9e8..b39f8032 100644 --- a/extensions/pagetop-bootsier/src/theme/navbar/brand.rs +++ b/extensions/pagetop-bootsier/src/theme/navbar/brand.rs @@ -59,7 +59,7 @@ impl Brand { /// Establece el identificador único (`id`) de la marca. #[builder_fn] pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); + self.id.alter_id(id); self } diff --git a/extensions/pagetop-bootsier/src/theme/navbar/component.rs b/extensions/pagetop-bootsier/src/theme/navbar/component.rs index 1f328fb0..26eeb43b 100644 --- a/extensions/pagetop-bootsier/src/theme/navbar/component.rs +++ b/extensions/pagetop-bootsier/src/theme/navbar/component.rs @@ -218,7 +218,7 @@ impl Navbar { /// Establece el identificador único (`id`) de la barra de navegación. #[builder_fn] pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); + self.id.alter_id(id); self } diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs b/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs index d5324397..4c3f979d 100644 --- a/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs +++ b/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs @@ -73,7 +73,7 @@ impl Offcanvas { /// Establece el identificador único (`id`) del panel. #[builder_fn] pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); + self.id.alter_id(id); self } diff --git a/src/base/action/component/after_render_component.rs b/src/base/action/component/after_render_component.rs index 7178404a..c4fddffe 100644 --- a/src/base/action/component/after_render_component.rs +++ b/src/base/action/component/after_render_component.rs @@ -42,7 +42,7 @@ impl AfterRender { /// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente /// `C` con identificador `id`. pub fn filter_by_referer_id(mut self, id: impl AsRef) -> Self { - self.referer_id.alter_value(id); + self.referer_id.alter_id(id); self } diff --git a/src/base/action/component/before_render_component.rs b/src/base/action/component/before_render_component.rs index 2c86d243..7f0b5b57 100644 --- a/src/base/action/component/before_render_component.rs +++ b/src/base/action/component/before_render_component.rs @@ -42,7 +42,7 @@ impl BeforeRender { /// Afina el registro para ejecutar la acción [`FnActionWithComponent`] sólo para el componente /// `C` con identificador `id`. pub fn filter_by_referer_id(mut self, id: impl AsRef) -> Self { - self.referer_id.alter_value(id); + self.referer_id.alter_id(id); self } diff --git a/src/base/component/block.rs b/src/base/component/block.rs index 4bdc4c03..98e08c32 100644 --- a/src/base/component/block.rs +++ b/src/base/component/block.rs @@ -55,7 +55,7 @@ impl Block { /// Establece el identificador único (`id`) del bloque. #[builder_fn] pub fn with_id(mut self, id: impl AsRef) -> Self { - self.id.alter_value(id); + self.id.alter_id(id); self } diff --git a/src/html.rs b/src/html.rs index 16a6c9e4..67285069 100644 --- a/src/html.rs +++ b/src/html.rs @@ -21,17 +21,8 @@ pub use logo::PageTopSvg; // **< HTML ATTRIBUTES >**************************************************************************** -mod attr_id; -pub use attr_id::AttrId; - -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; +pub use attr::{Attr, AttrId, AttrName, AttrValue}; mod attr_classes; pub use attr_classes::{AttrClasses, ClassesOp}; diff --git a/src/html/attr.rs b/src/html/attr.rs new file mode 100644 index 00000000..01c78280 --- /dev/null +++ b/src/html/attr.rs @@ -0,0 +1,321 @@ +use crate::locale::{L10n, LangId}; +use crate::{builder_fn, AutoDefault}; + +/// Valor opcional para atributos HTML. +/// +/// `Attr` encapsula un `Option` 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` y `Attr`, o en tipos específicos como +/// [`AttrId`] y [`AttrName`]. +#[derive(AutoDefault, Clone, Debug)] +pub struct Attr(Option); + +impl Attr { + /// 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 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 GETTERS >************************************************************************ + + /// Devuelve el valor (clonado), si existe. + pub fn get(&self) -> Option + 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 { + self.0 + } + + /// `true` si no hay valor. + pub fn is_empty(&self) -> bool { + self.0.is_none() + } +} + +// **< Attr >********************************************************************************* + +/// 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::::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 { + /// Crea una nueva instancia `Attr`. + 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 { + 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 >******************************************************************************* + +/// Extiende [`Attr`] para cadenas de texto. +impl Attr { + /// 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` 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); + +impl AttrId { + /// Crea un nuevo `AttrId` normalizando el valor. + pub fn new(id: impl AsRef) -> 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) -> 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 { + 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 { + 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` 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); + +impl AttrName { + /// Crea un nuevo `AttrName` normalizando el valor. + pub fn new(name: impl AsRef) -> 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) -> 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 { + 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 { + 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` 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); + +impl AttrValue { + /// Crea un nuevo `AttrValue` normalizando el valor. + pub fn new(value: impl AsRef) -> 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) -> 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 { + 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 { + self.0.into_inner() + } + + /// `true` si no hay valor. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} diff --git a/src/html/attr_id.rs b/src/html/attr_id.rs deleted file mode 100644 index a1d8a1da..00000000 --- a/src/html/attr_id.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::{builder_fn, AutoDefault}; - -/// Identificador normalizado para el atributo `id` o similar de HTML. -/// -/// Este tipo encapsula `Option` 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); - -impl AttrId { - /// Crea un nuevo `AttrId` normalizando el valor. - pub fn new(value: impl AsRef) -> 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) -> 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 { - 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 { - self.0 - } - - /// `true` si no hay valor. - pub fn is_empty(&self) -> bool { - self.0.is_none() - } -} diff --git a/src/html/attr_l10n.rs b/src/html/attr_l10n.rs deleted file mode 100644 index aa18f6c2..00000000 --- a/src/html/attr_l10n.rs +++ /dev/null @@ -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 { - 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() - } -} diff --git a/src/html/attr_name.rs b/src/html/attr_name.rs deleted file mode 100644 index 1741695c..00000000 --- a/src/html/attr_name.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::{builder_fn, AutoDefault}; - -/// Nombre normalizado para el atributo `name` o similar de HTML. -/// -/// Este tipo encapsula `Option` 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); - -impl AttrName { - /// Crea un nuevo `AttrName` normalizando el valor. - pub fn new(value: impl AsRef) -> 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) -> 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 { - 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 { - self.0 - } - - /// `true` si no hay valor. - pub fn is_empty(&self) -> bool { - self.0.is_none() - } -} diff --git a/src/html/attr_value.rs b/src/html/attr_value.rs deleted file mode 100644 index b20dec3d..00000000 --- a/src/html/attr_value.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::{builder_fn, AutoDefault}; - -/// Cadena normalizada para renderizar en atributos HTML. -/// -/// Este tipo encapsula `Option` 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); - -impl AttrValue { - /// Crea un nuevo `AttrValue` normalizando el valor. - pub fn new(value: impl AsRef) -> 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) -> 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 { - 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 { - self.0 - } - - /// `true` si no hay valor. - pub fn is_empty(&self) -> bool { - self.0.is_none() - } -} diff --git a/src/response/page.rs b/src/response/page.rs index 41d0a125..1384fcd7 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -24,8 +24,8 @@ use crate::core::component::{Context, ContextOp, Contextual}; use crate::core::theme::{DefaultRegion, Region, RegionRef, TemplateRef, ThemeRef}; use crate::html::{html, Markup, DOCTYPE}; use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; +use crate::html::{Attr, AttrId}; use crate::html::{AttrClasses, ClassesOp}; -use crate::html::{AttrId, AttrL10n}; use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier}; use crate::service::HttpRequest; use crate::{builder_fn, AutoDefault}; @@ -89,8 +89,8 @@ impl Region for ReservedRegion { #[rustfmt::skip] #[derive(AutoDefault)] pub struct Page { - title : AttrL10n, - description : AttrL10n, + title : Attr, + description : Attr, metadata : Vec<(&'static str, &'static str)>, properties : Vec<(&'static str, &'static str)>, body_id : AttrId, @@ -106,8 +106,8 @@ impl Page { #[rustfmt::skip] pub fn new(request: HttpRequest) -> Self { Page { - title : AttrL10n::default(), - description : AttrL10n::default(), + title : Attr::::default(), + description : Attr::::default(), metadata : Vec::default(), properties : Vec::default(), body_id : AttrId::default(), @@ -149,7 +149,7 @@ impl Page { /// Establece el atributo `id` del elemento ``. #[builder_fn] pub fn with_body_id(mut self, id: impl AsRef) -> Self { - self.body_id.alter_value(id); + self.body_id.alter_id(id); self }