♻️ 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.
|
||||
#[builder_fn]
|
||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self.id.alter_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<str>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self.id.alter_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -263,7 +263,7 @@ impl Item {
|
|||
/// Establece el identificador único (`id`) del elemento.
|
||||
#[builder_fn]
|
||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self.id.alter_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<L10n>,
|
||||
}
|
||||
|
||||
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<str>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self.id.alter_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ impl Nav {
|
|||
/// Establece el identificador único (`id`) del menú.
|
||||
#[builder_fn]
|
||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self.id.alter_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ impl Item {
|
|||
/// Establece el identificador único (`id`) del elemento.
|
||||
#[builder_fn]
|
||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self.id.alter_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<str>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self.id.alter_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<str>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self.id.alter_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ impl Offcanvas {
|
|||
/// Establece el identificador único (`id`) del panel.
|
||||
#[builder_fn]
|
||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self.id.alter_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ impl<C: Component> AfterRender<C> {
|
|||
/// 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<str>) -> Self {
|
||||
self.referer_id.alter_value(id);
|
||||
self.referer_id.alter_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ impl<C: Component> BeforeRender<C> {
|
|||
/// 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<str>) -> Self {
|
||||
self.referer_id.alter_value(id);
|
||||
self.referer_id.alter_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ impl Block {
|
|||
/// Establece el identificador único (`id`) del bloque.
|
||||
#[builder_fn]
|
||||
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
|
||||
self.id.alter_value(id);
|
||||
self.id.alter_id(id);
|
||||
self
|
||||
}
|
||||
|
||||
|
|
|
|||
13
src/html.rs
13
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};
|
||||
|
|
|
|||
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::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<L10n>,
|
||||
description : Attr<L10n>,
|
||||
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::<L10n>::default(),
|
||||
description : Attr::<L10n>::default(),
|
||||
metadata : Vec::default(),
|
||||
properties : Vec::default(),
|
||||
body_id : AttrId::default(),
|
||||
|
|
@ -149,7 +149,7 @@ impl Page {
|
|||
/// Establece el atributo `id` del elemento `<body>`.
|
||||
#[builder_fn]
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue