♻️ [html] Cambia tipos Option...
por Attr...
Renombra los tipos para atributos HTML `Id`, `Name`, `Value` (`String`), `L10n` (`Translate`) y `Classes`. Y mueve `OptionComponent` al *core* de componentes como `TypedSlot`.
This commit is contained in:
parent
75eec8bebc
commit
bb34ba5887
17 changed files with 367 additions and 311 deletions
|
@ -6,7 +6,7 @@ use crate::base::action::FnActionWithComponent;
|
||||||
pub struct AfterRender<C: Component> {
|
pub struct AfterRender<C: Component> {
|
||||||
f: FnActionWithComponent<C>,
|
f: FnActionWithComponent<C>,
|
||||||
referer_type_id: Option<UniqueId>,
|
referer_type_id: Option<UniqueId>,
|
||||||
referer_id: OptionId,
|
referer_id: AttrId,
|
||||||
weight: Weight,
|
weight: Weight,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ impl<C: Component> AfterRender<C> {
|
||||||
AfterRender {
|
AfterRender {
|
||||||
f,
|
f,
|
||||||
referer_type_id: Some(UniqueId::of::<C>()),
|
referer_type_id: Some(UniqueId::of::<C>()),
|
||||||
referer_id: OptionId::default(),
|
referer_id: AttrId::default(),
|
||||||
weight: 0,
|
weight: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::base::action::FnActionWithComponent;
|
||||||
pub struct BeforeRender<C: Component> {
|
pub struct BeforeRender<C: Component> {
|
||||||
f: FnActionWithComponent<C>,
|
f: FnActionWithComponent<C>,
|
||||||
referer_type_id: Option<UniqueId>,
|
referer_type_id: Option<UniqueId>,
|
||||||
referer_id: OptionId,
|
referer_id: AttrId,
|
||||||
weight: Weight,
|
weight: Weight,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ impl<C: Component> BeforeRender<C> {
|
||||||
BeforeRender {
|
BeforeRender {
|
||||||
f,
|
f,
|
||||||
referer_type_id: Some(UniqueId::of::<C>()),
|
referer_type_id: Some(UniqueId::of::<C>()),
|
||||||
referer_id: OptionId::default(),
|
referer_id: AttrId::default(),
|
||||||
weight: 0,
|
weight: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ pub type FnIsRenderable<C> = fn(component: &C, cx: &Context) -> bool;
|
||||||
pub struct IsRenderable<C: Component> {
|
pub struct IsRenderable<C: Component> {
|
||||||
f: FnIsRenderable<C>,
|
f: FnIsRenderable<C>,
|
||||||
referer_type_id: Option<UniqueId>,
|
referer_type_id: Option<UniqueId>,
|
||||||
referer_id: OptionId,
|
referer_id: AttrId,
|
||||||
weight: Weight,
|
weight: Weight,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ impl<C: Component> IsRenderable<C> {
|
||||||
IsRenderable {
|
IsRenderable {
|
||||||
f,
|
f,
|
||||||
referer_type_id: Some(UniqueId::of::<C>()),
|
referer_type_id: Some(UniqueId::of::<C>()),
|
||||||
referer_id: OptionId::default(),
|
referer_id: AttrId::default(),
|
||||||
weight: 0,
|
weight: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,3 +7,6 @@ mod children;
|
||||||
pub use children::Children;
|
pub use children::Children;
|
||||||
pub use children::{Child, ChildOp};
|
pub use children::{Child, ChildOp};
|
||||||
pub use children::{Typed, TypedOp};
|
pub use children::{Typed, TypedOp};
|
||||||
|
|
||||||
|
mod slot;
|
||||||
|
pub use slot::TypedSlot;
|
||||||
|
|
|
@ -9,13 +9,13 @@ use std::vec::IntoIter;
|
||||||
|
|
||||||
/// Representa un componente encapsulado de forma segura y compartida.
|
/// Representa un componente encapsulado de forma segura y compartida.
|
||||||
///
|
///
|
||||||
/// Esta estructura permite manipular y renderizar cualquier tipo que implemente [`Component`],
|
/// Esta estructura permite manipular y renderizar un componente que implemente [`Component`], y
|
||||||
/// garantizando acceso concurrente a través de [`Arc<RwLock<_>>`].
|
/// habilita acceso concurrente mediante [`Arc<RwLock<_>>`].
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Child(Arc<RwLock<dyn Component>>);
|
pub struct Child(Arc<RwLock<dyn Component>>);
|
||||||
|
|
||||||
impl Child {
|
impl Child {
|
||||||
/// Crea un nuevo [`Child`] a partir de un componente.
|
/// Crea un nuevo `Child` a partir de un componente.
|
||||||
pub fn with(component: impl Component) -> Self {
|
pub fn with(component: impl Component) -> Self {
|
||||||
Child(Arc::new(RwLock::new(component)))
|
Child(Arc::new(RwLock::new(component)))
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,8 @@ impl Child {
|
||||||
|
|
||||||
/// Variante tipada de [`Child`] para evitar conversiones durante el uso.
|
/// Variante tipada de [`Child`] para evitar conversiones durante el uso.
|
||||||
///
|
///
|
||||||
/// Facilita el acceso a componentes del mismo tipo sin necesidad de hacer `downcast`.
|
/// Esta estructura permite manipular y renderizar un componente concreto que implemente
|
||||||
|
/// [`Component`], y habilita acceso concurrente mediante [`Arc<RwLock<_>>`].
|
||||||
pub struct Typed<C: Component>(Arc<RwLock<C>>);
|
pub struct Typed<C: Component>(Arc<RwLock<C>>);
|
||||||
|
|
||||||
impl<C: Component> Clone for Typed<C> {
|
impl<C: Component> Clone for Typed<C> {
|
||||||
|
@ -56,7 +57,7 @@ impl<C: Component> Clone for Typed<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: Component> Typed<C> {
|
impl<C: Component> Typed<C> {
|
||||||
/// Crea un nuevo [`Typed`] a partir de un componente.
|
/// Crea un nuevo `Typed` a partir de un componente.
|
||||||
pub fn with(component: C) -> Self {
|
pub fn with(component: C) -> Self {
|
||||||
Typed(Arc::new(RwLock::new(component)))
|
Typed(Arc::new(RwLock::new(component)))
|
||||||
}
|
}
|
||||||
|
@ -284,7 +285,7 @@ impl IntoIterator for Children {
|
||||||
///
|
///
|
||||||
/// # Ejemplo de uso:
|
/// # Ejemplo de uso:
|
||||||
///
|
///
|
||||||
/// ```rust#ignore
|
/// ```rust,ignore
|
||||||
/// let children = Children::new().with(child1).with(child2);
|
/// let children = Children::new().with(child1).with(child2);
|
||||||
/// for child in children {
|
/// for child in children {
|
||||||
/// println!("{:?}", child.id());
|
/// println!("{:?}", child.id());
|
||||||
|
@ -303,7 +304,7 @@ impl<'a> IntoIterator for &'a Children {
|
||||||
///
|
///
|
||||||
/// # Ejemplo de uso:
|
/// # Ejemplo de uso:
|
||||||
///
|
///
|
||||||
/// ```rust#ignore
|
/// ```rust,ignore
|
||||||
/// let children = Children::new().with(child1).with(child2);
|
/// let children = Children::new().with(child1).with(child2);
|
||||||
/// for child in &children {
|
/// for child in &children {
|
||||||
/// println!("{:?}", child.id());
|
/// println!("{:?}", child.id());
|
||||||
|
@ -322,7 +323,7 @@ impl<'a> IntoIterator for &'a mut Children {
|
||||||
///
|
///
|
||||||
/// # Ejemplo de uso:
|
/// # Ejemplo de uso:
|
||||||
///
|
///
|
||||||
/// ```rust#ignore
|
/// ```rust,ignore
|
||||||
/// let mut children = Children::new().with(child1).with(child2);
|
/// let mut children = Children::new().with(child1).with(child2);
|
||||||
/// for child in &mut children {
|
/// for child in &mut children {
|
||||||
/// child.render(&mut context);
|
/// child.render(&mut context);
|
||||||
|
|
64
src/core/component/slot.rs
Normal file
64
src/core/component/slot.rs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
use crate::builder_fn;
|
||||||
|
use crate::core::component::{Component, Typed};
|
||||||
|
use crate::html::{html, Context, Markup};
|
||||||
|
|
||||||
|
/// Contenedor para un componente [`Typed`] opcional.
|
||||||
|
///
|
||||||
|
/// Un `TypedSlot` actúa como un contenedor dentro de otro componente para incluir o no un
|
||||||
|
/// subcomponente. Internamente encapsula `Option<Typed<C>>`, pero proporciona una API más sencilla
|
||||||
|
/// para construir estructuras jerárquicas.
|
||||||
|
///
|
||||||
|
/// # Ejemplo
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// use pagetop::prelude::*;
|
||||||
|
///
|
||||||
|
/// let comp = MyComponent::new();
|
||||||
|
/// let opt = TypedSlot::new(comp);
|
||||||
|
/// assert!(opt.get().is_some());
|
||||||
|
/// ```
|
||||||
|
pub struct TypedSlot<C: Component>(Option<Typed<C>>);
|
||||||
|
|
||||||
|
impl<C: Component> Default for TypedSlot<C> {
|
||||||
|
fn default() -> Self {
|
||||||
|
TypedSlot(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: Component> TypedSlot<C> {
|
||||||
|
/// Crea un nuevo [`TypedSlot`].
|
||||||
|
///
|
||||||
|
/// El componente se envuelve automáticamente en un [`Typed`] y se almacena.
|
||||||
|
pub fn new(component: C) -> Self {
|
||||||
|
TypedSlot(Some(Typed::with(component)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypedSlot BUILDER *********************************************************************
|
||||||
|
|
||||||
|
/// Establece un componente nuevo, o lo vacía.
|
||||||
|
///
|
||||||
|
/// Si se proporciona `Some(component)`, se guarda en [`Typed`]; y si es `None`, se limpia.
|
||||||
|
#[builder_fn]
|
||||||
|
pub fn with_value(mut self, component: Option<C>) -> Self {
|
||||||
|
self.0 = component.map(Typed::with);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypedSlot GETTERS *********************************************************************
|
||||||
|
|
||||||
|
/// Devuelve un clon (incrementa el contador `Arc`) de [`Typed<C>`], si existe.
|
||||||
|
pub fn get(&self) -> Option<Typed<C>> {
|
||||||
|
self.0.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypedSlot RENDER ************************************************************************
|
||||||
|
|
||||||
|
/// Renderiza el componente, si existe.
|
||||||
|
pub fn render(&self, cx: &mut Context) -> Markup {
|
||||||
|
if let Some(component) = &self.0 {
|
||||||
|
component.render(cx)
|
||||||
|
} else {
|
||||||
|
html! {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
90
src/html.rs
90
src/html.rs
|
@ -3,52 +3,82 @@
|
||||||
mod maud;
|
mod maud;
|
||||||
pub use maud::{display, html, html_private, Escaper, Markup, PreEscaped, Render, DOCTYPE};
|
pub use maud::{display, html, html_private, Escaper, Markup, PreEscaped, Render, DOCTYPE};
|
||||||
|
|
||||||
|
// HTML DOCUMENT ASSETS ****************************************************************************
|
||||||
|
|
||||||
mod assets;
|
mod assets;
|
||||||
pub use assets::favicon::Favicon;
|
pub use assets::favicon::Favicon;
|
||||||
pub use assets::javascript::JavaScript;
|
pub use assets::javascript::JavaScript;
|
||||||
pub use assets::stylesheet::{StyleSheet, TargetMedia};
|
pub use assets::stylesheet::{StyleSheet, TargetMedia};
|
||||||
pub(crate) use assets::Assets;
|
pub(crate) use assets::Assets;
|
||||||
|
|
||||||
|
// HTML DOCUMENT CONTEXT ***************************************************************************
|
||||||
|
|
||||||
mod context;
|
mod context;
|
||||||
pub use context::{AssetsOp, Context, ErrorParam};
|
pub use context::{AssetsOp, Context, ErrorParam};
|
||||||
|
|
||||||
mod opt_id;
|
// HTML ATTRIBUTES *********************************************************************************
|
||||||
pub use opt_id::OptionId;
|
|
||||||
|
|
||||||
mod opt_name;
|
mod attr_id;
|
||||||
pub use opt_name::OptionName;
|
pub use attr_id::AttrId;
|
||||||
|
/// **Obsoleto desde la versión 0.4.0**: usar [`AttrId`] en su lugar.
|
||||||
|
#[deprecated(since = "0.4.0", note = "Use `AttrId` instead")]
|
||||||
|
pub type OptionId = AttrId;
|
||||||
|
|
||||||
mod opt_string;
|
mod attr_name;
|
||||||
pub use opt_string::OptionString;
|
pub use attr_name::AttrName;
|
||||||
|
/// **Obsoleto desde la versión 0.4.0**: usar [`AttrName`] en su lugar.
|
||||||
|
#[deprecated(since = "0.4.0", note = "Use `AttrName` instead")]
|
||||||
|
pub type OptionName = AttrName;
|
||||||
|
|
||||||
mod opt_translated;
|
mod attr_value;
|
||||||
pub use opt_translated::OptionTranslated;
|
pub use attr_value::AttrValue;
|
||||||
|
/// **Obsoleto desde la versión 0.4.0**: usar [`AttrValue`] en su lugar.
|
||||||
|
#[deprecated(since = "0.4.0", note = "Use `AttrValue` instead")]
|
||||||
|
pub type OptionString = AttrValue;
|
||||||
|
|
||||||
mod opt_classes;
|
mod attr_l10n;
|
||||||
pub use opt_classes::{ClassesOp, OptionClasses};
|
pub use attr_l10n::AttrL10n;
|
||||||
|
/// **Obsoleto desde la versión 0.4.0**: usar [`AttrL10n`] en su lugar.
|
||||||
|
#[deprecated(since = "0.4.0", note = "Use `AttrL10n` instead")]
|
||||||
|
pub type OptionTranslated = AttrL10n;
|
||||||
|
|
||||||
mod opt_component;
|
mod attr_classes;
|
||||||
pub use opt_component::OptionComponent;
|
pub use attr_classes::{AttrClasses, ClassesOp};
|
||||||
|
/// **Obsoleto desde la versión 0.4.0**: usar [`AttrClasses`] en su lugar.
|
||||||
|
#[deprecated(since = "0.4.0", note = "Use `AttrClasses` instead")]
|
||||||
|
pub type OptionClasses = AttrClasses;
|
||||||
|
|
||||||
use crate::AutoDefault;
|
use crate::{core, AutoDefault};
|
||||||
|
|
||||||
|
/// **Obsoleto desde la versión 0.4.0**: usar [`TypedSlot`](crate::core::component::TypedSlot) en su
|
||||||
|
/// lugar.
|
||||||
|
#[deprecated(
|
||||||
|
since = "0.4.0",
|
||||||
|
note = "Use `pagetop::core::component::TypedSlot` instead"
|
||||||
|
)]
|
||||||
|
#[allow(type_alias_bounds)]
|
||||||
|
pub type OptionComponent<C: core::component::Component> = core::component::TypedSlot<C>;
|
||||||
|
|
||||||
/// Prepara contenido HTML para su conversión a [`Markup`].
|
/// Prepara contenido HTML para su conversión a [`Markup`].
|
||||||
///
|
///
|
||||||
/// Este tipo encapsula distintos orígenes de contenido HTML (texto plano, HTML escapado o marcado
|
/// Este tipo encapsula distintos orígenes de contenido HTML (texto plano, HTML sin escapar o
|
||||||
/// ya procesado) para renderizar de forma homogénea en plantillas sin interferir con el uso
|
/// fragmentos ya procesados) para renderizarlos de forma homogénea en plantillas, sin interferir
|
||||||
/// estándar de [`Markup`].
|
/// con el uso estándar de [`Markup`].
|
||||||
///
|
///
|
||||||
/// # Ejemplo
|
/// # Ejemplo
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use pagetop::prelude::*;
|
/// use pagetop::prelude::*;
|
||||||
///
|
///
|
||||||
/// let fragment = PrepareMarkup::Text(String::from("Hola <b>mundo</b>"));
|
/// // Texto normal, se escapa automáticamente para evitar inyección de HTML.
|
||||||
|
/// let fragment = PrepareMarkup::Escaped(String::from("Hola <b>mundo</b>"));
|
||||||
/// assert_eq!(fragment.render().into_string(), "Hola <b>mundo</b>");
|
/// assert_eq!(fragment.render().into_string(), "Hola <b>mundo</b>");
|
||||||
///
|
///
|
||||||
/// let raw_html = PrepareMarkup::Escaped(String::from("<b>negrita</b>"));
|
/// // HTML literal, se inserta directamente, sin escapado adicional.
|
||||||
|
/// let raw_html = PrepareMarkup::Raw(String::from("<b>negrita</b>"));
|
||||||
/// assert_eq!(raw_html.render().into_string(), "<b>negrita</b>");
|
/// assert_eq!(raw_html.render().into_string(), "<b>negrita</b>");
|
||||||
///
|
///
|
||||||
|
/// // Fragmento ya preparado con la macro `html!`.
|
||||||
/// let prepared = PrepareMarkup::With(html! {
|
/// let prepared = PrepareMarkup::With(html! {
|
||||||
/// h2 { "Título de ejemplo" }
|
/// h2 { "Título de ejemplo" }
|
||||||
/// p { "Este es un párrafo con contenido dinámico." }
|
/// p { "Este es un párrafo con contenido dinámico." }
|
||||||
|
@ -60,14 +90,22 @@ use crate::AutoDefault;
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(AutoDefault)]
|
#[derive(AutoDefault)]
|
||||||
pub enum PrepareMarkup {
|
pub enum PrepareMarkup {
|
||||||
/// No se genera contenido HTML (devuelve `html! {}`).
|
/// No se genera contenido HTML (equivale a `html! {}`).
|
||||||
#[default]
|
#[default]
|
||||||
None,
|
None,
|
||||||
/// Texto estático que se escapará automáticamente para no ser interpretado como HTML.
|
/// Texto plano que se **escapará automáticamente** para que no sea interpretado como HTML.
|
||||||
Text(String),
|
///
|
||||||
/// Contenido sin escapado adicional, útil para HTML generado externamente.
|
/// Úsalo con textos que provengan de usuarios u otras fuentes externas para garantizar la
|
||||||
|
/// seguridad contra inyección de código.
|
||||||
Escaped(String),
|
Escaped(String),
|
||||||
|
/// HTML literal que se inserta **sin escapado adicional**.
|
||||||
|
///
|
||||||
|
/// Úsalo únicamente para contenido generado de forma confiable o controlada, ya que cualquier
|
||||||
|
/// etiqueta o script incluido será renderizado directamente en el documento.
|
||||||
|
Raw(String),
|
||||||
/// Fragmento HTML ya preparado como [`Markup`], listo para insertarse directamente.
|
/// Fragmento HTML ya preparado como [`Markup`], listo para insertarse directamente.
|
||||||
|
///
|
||||||
|
/// Normalmente proviene de expresiones `html! { ... }`.
|
||||||
With(Markup),
|
With(Markup),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,8 +114,8 @@ impl PrepareMarkup {
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
PrepareMarkup::None => true,
|
PrepareMarkup::None => true,
|
||||||
PrepareMarkup::Text(text) => text.is_empty(),
|
PrepareMarkup::Escaped(text) => text.is_empty(),
|
||||||
PrepareMarkup::Escaped(string) => string.is_empty(),
|
PrepareMarkup::Raw(string) => string.is_empty(),
|
||||||
PrepareMarkup::With(markup) => markup.is_empty(),
|
PrepareMarkup::With(markup) => markup.is_empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,8 +126,8 @@ impl Render for PrepareMarkup {
|
||||||
fn render(&self) -> Markup {
|
fn render(&self) -> Markup {
|
||||||
match self {
|
match self {
|
||||||
PrepareMarkup::None => html! {},
|
PrepareMarkup::None => html! {},
|
||||||
PrepareMarkup::Text(text) => html! { (text) },
|
PrepareMarkup::Escaped(text) => html! { (text) },
|
||||||
PrepareMarkup::Escaped(string) => html! { (PreEscaped(string)) },
|
PrepareMarkup::Raw(string) => html! { (PreEscaped(string)) },
|
||||||
PrepareMarkup::With(markup) => html! { (markup) },
|
PrepareMarkup::With(markup) => html! { (markup) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{builder_fn, AutoDefault};
|
use crate::{builder_fn, AutoDefault};
|
||||||
|
|
||||||
/// Operaciones disponibles sobre la lista de clases en [`OptionClasses`].
|
/// Operaciones disponibles sobre la lista de clases en [`AttrClasses`].
|
||||||
pub enum ClassesOp {
|
pub enum ClassesOp {
|
||||||
/// Añade al final (si no existe).
|
/// Añade al final (si no existe).
|
||||||
Add,
|
Add,
|
||||||
|
@ -33,7 +33,7 @@ pub enum ClassesOp {
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use pagetop::prelude::*;
|
/// use pagetop::prelude::*;
|
||||||
///
|
///
|
||||||
/// let classes = OptionClasses::new("Btn btn-primary")
|
/// let classes = AttrClasses::new("Btn btn-primary")
|
||||||
/// .with_value(ClassesOp::Add, "Active")
|
/// .with_value(ClassesOp::Add, "Active")
|
||||||
/// .with_value(ClassesOp::Remove, "btn-primary");
|
/// .with_value(ClassesOp::Remove, "btn-primary");
|
||||||
///
|
///
|
||||||
|
@ -41,14 +41,14 @@ pub enum ClassesOp {
|
||||||
/// assert!(classes.contains("active"));
|
/// assert!(classes.contains("active"));
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(AutoDefault, Clone, Debug)]
|
#[derive(AutoDefault, Clone, Debug)]
|
||||||
pub struct OptionClasses(Vec<String>);
|
pub struct AttrClasses(Vec<String>);
|
||||||
|
|
||||||
impl OptionClasses {
|
impl AttrClasses {
|
||||||
pub fn new(classes: impl AsRef<str>) -> Self {
|
pub fn new(classes: impl AsRef<str>) -> Self {
|
||||||
OptionClasses::default().with_value(ClassesOp::Prepend, classes)
|
AttrClasses::default().with_value(ClassesOp::Prepend, classes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OptionClasses BUILDER ***********************************************************************
|
// AttrClasses BUILDER *************************************************************************
|
||||||
|
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_value(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
|
pub fn with_value(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
|
||||||
|
@ -114,7 +114,7 @@ impl OptionClasses {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// OptionClasses GETTERS ***********************************************************************
|
// AttrClasses GETTERS *************************************************************************
|
||||||
|
|
||||||
/// Devuele la cadena de clases, si existe.
|
/// Devuele la cadena de clases, si existe.
|
||||||
pub fn get(&self) -> Option<String> {
|
pub fn get(&self) -> Option<String> {
|
63
src/html/attr_id.rs
Normal file
63
src/html/attr_id.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ use crate::html::Markup;
|
||||||
use crate::locale::{L10n, LangId};
|
use crate::locale::{L10n, LangId};
|
||||||
use crate::{builder_fn, AutoDefault};
|
use crate::{builder_fn, AutoDefault};
|
||||||
|
|
||||||
/// Cadena para traducir al renderizar ([`locale`](crate::locale)).
|
/// Texto para [traducir](crate::locale) en atributos HTML.
|
||||||
///
|
///
|
||||||
/// Encapsula un tipo [`L10n`] para manejar traducciones de forma segura.
|
/// Encapsula un tipo [`L10n`] para manejar traducciones de forma segura.
|
||||||
///
|
///
|
||||||
|
@ -12,7 +12,7 @@ use crate::{builder_fn, AutoDefault};
|
||||||
/// use pagetop::prelude::*;
|
/// use pagetop::prelude::*;
|
||||||
///
|
///
|
||||||
/// // Traducción por clave en las locales por defecto de PageTop.
|
/// // Traducción por clave en las locales por defecto de PageTop.
|
||||||
/// let hello = OptionTranslated::new(L10n::l("test-hello-world"));
|
/// let hello = AttrL10n::new(L10n::l("test-hello-world"));
|
||||||
///
|
///
|
||||||
/// // Español disponible.
|
/// // Español disponible.
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
|
@ -31,15 +31,15 @@ use crate::{builder_fn, AutoDefault};
|
||||||
/// assert_eq!(markup.into_string(), "¡Hola mundo!");
|
/// assert_eq!(markup.into_string(), "¡Hola mundo!");
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(AutoDefault, Clone, Debug)]
|
#[derive(AutoDefault, Clone, Debug)]
|
||||||
pub struct OptionTranslated(L10n);
|
pub struct AttrL10n(L10n);
|
||||||
|
|
||||||
impl OptionTranslated {
|
impl AttrL10n {
|
||||||
/// Crea una nueva instancia [`OptionTranslated`].
|
/// Crea una nueva instancia `AttrL10n`.
|
||||||
pub fn new(value: L10n) -> Self {
|
pub fn new(value: L10n) -> Self {
|
||||||
OptionTranslated(value)
|
AttrL10n(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OptionTranslated BUILDER ********************************************************************
|
// AttrL10n BUILDER ****************************************************************************
|
||||||
|
|
||||||
/// Establece una traducción nueva.
|
/// Establece una traducción nueva.
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
|
@ -48,7 +48,7 @@ impl OptionTranslated {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
// OptionTranslated GETTERS ********************************************************************
|
// AttrL10n GETTERS ****************************************************************************
|
||||||
|
|
||||||
/// Devuelve la traducción para `language`, si existe.
|
/// Devuelve la traducción para `language`, si existe.
|
||||||
pub fn using(&self, language: &impl LangId) -> Option<String> {
|
pub fn using(&self, language: &impl LangId) -> Option<String> {
|
63
src/html/attr_name.rs
Normal file
63
src/html/attr_name.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
65
src/html/attr_value.rs
Normal file
65
src/html/attr_value.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
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_owned())
|
||||||
|
};
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,68 +0,0 @@
|
||||||
use crate::builder_fn;
|
|
||||||
use crate::core::component::{Component, Typed};
|
|
||||||
use crate::html::{html, Context, Markup};
|
|
||||||
|
|
||||||
/// Contenedor de componente para incluir en otros componentes.
|
|
||||||
///
|
|
||||||
/// Este tipo encapsula `Option<Typed<C>>` para incluir un componente de manera segura en otros
|
|
||||||
/// componentes, útil para representar estructuras complejas.
|
|
||||||
///
|
|
||||||
/// # Ejemplo
|
|
||||||
///
|
|
||||||
/// ```rust,ignore
|
|
||||||
/// use pagetop::prelude::*;
|
|
||||||
///
|
|
||||||
/// let comp = MyComponent::new();
|
|
||||||
/// let opt = OptionComponent::new(comp);
|
|
||||||
/// assert!(opt.get().is_some());
|
|
||||||
/// ```
|
|
||||||
pub struct OptionComponent<C: Component>(Option<Typed<C>>);
|
|
||||||
|
|
||||||
impl<C: Component> Default for OptionComponent<C> {
|
|
||||||
fn default() -> Self {
|
|
||||||
OptionComponent(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C: Component> OptionComponent<C> {
|
|
||||||
/// Crea un nuevo [`OptionComponent`].
|
|
||||||
///
|
|
||||||
/// El componente se envuelve automáticamente en un [`Typed`] y se almacena.
|
|
||||||
pub fn new(component: C) -> Self {
|
|
||||||
OptionComponent::default().with_value(Some(component))
|
|
||||||
}
|
|
||||||
|
|
||||||
// OptionComponent BUILDER *********************************************************************
|
|
||||||
|
|
||||||
/// Establece un componente nuevo, o lo vacía.
|
|
||||||
///
|
|
||||||
/// Si se proporciona `Some(component)`, se guarda en [`Typed`]; y si es `None`, se limpia.
|
|
||||||
#[builder_fn]
|
|
||||||
pub fn with_value(mut self, component: Option<C>) -> Self {
|
|
||||||
if let Some(component) = component {
|
|
||||||
self.0 = Some(Typed::with(component));
|
|
||||||
} else {
|
|
||||||
self.0 = None;
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
// OptionComponent GETTERS *********************************************************************
|
|
||||||
|
|
||||||
/// Devuelve el componente, si existe.
|
|
||||||
pub fn get(&self) -> Option<Typed<C>> {
|
|
||||||
if let Some(value) = &self.0 {
|
|
||||||
return Some(value.clone());
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Renderiza el componente, si existe.
|
|
||||||
pub fn render(&self, cx: &mut Context) -> Markup {
|
|
||||||
if let Some(component) = &self.0 {
|
|
||||||
component.render(cx)
|
|
||||||
} else {
|
|
||||||
html! {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +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.
|
|
||||||
///
|
|
||||||
/// # Normalización
|
|
||||||
///
|
|
||||||
/// - 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 = OptionId::new(" main Section ");
|
|
||||||
/// assert_eq!(id.get(), Some(String::from("main_section")));
|
|
||||||
///
|
|
||||||
/// let empty = OptionId::default();
|
|
||||||
/// assert_eq!(empty.get(), None);
|
|
||||||
/// ```
|
|
||||||
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
|
|
||||||
pub struct OptionId(Option<String>);
|
|
||||||
|
|
||||||
impl OptionId {
|
|
||||||
/// Crea un nuevo [`OptionId`].
|
|
||||||
///
|
|
||||||
/// El valor se normaliza automáticamente.
|
|
||||||
pub fn new(value: impl AsRef<str>) -> Self {
|
|
||||||
OptionId::default().with_value(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OptionId BUILDER ****************************************************************************
|
|
||||||
|
|
||||||
/// Establece un identificador nuevo.
|
|
||||||
///
|
|
||||||
/// El valor se normaliza automáticamente.
|
|
||||||
#[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 = (!value.is_empty()).then_some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
// OptionId GETTERS ****************************************************************************
|
|
||||||
|
|
||||||
/// Devuelve el identificador, si existe.
|
|
||||||
pub fn get(&self) -> Option<String> {
|
|
||||||
if let Some(value) = &self.0 {
|
|
||||||
if !value.is_empty() {
|
|
||||||
return Some(value.to_owned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +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.
|
|
||||||
///
|
|
||||||
/// # Normalización
|
|
||||||
///
|
|
||||||
/// - 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 = OptionName::new(" DISplay name ");
|
|
||||||
/// assert_eq!(name.get(), Some(String::from("display_name")));
|
|
||||||
///
|
|
||||||
/// let empty = OptionName::default();
|
|
||||||
/// assert_eq!(empty.get(), None);
|
|
||||||
/// ```
|
|
||||||
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
|
|
||||||
pub struct OptionName(Option<String>);
|
|
||||||
|
|
||||||
impl OptionName {
|
|
||||||
/// Crea un nuevo [`OptionName`].
|
|
||||||
///
|
|
||||||
/// El valor se normaliza automáticamente.
|
|
||||||
pub fn new(value: impl AsRef<str>) -> Self {
|
|
||||||
OptionName::default().with_value(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OptionName BUILDER **************************************************************************
|
|
||||||
|
|
||||||
/// Establece un nombre nuevo.
|
|
||||||
///
|
|
||||||
/// El valor se normaliza automáticamente.
|
|
||||||
#[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 = (!value.is_empty()).then_some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
// OptionName GETTERS **************************************************************************
|
|
||||||
|
|
||||||
/// Devuelve el nombre, si existe.
|
|
||||||
pub fn get(&self) -> Option<String> {
|
|
||||||
if let Some(value) = &self.0 {
|
|
||||||
if !value.is_empty() {
|
|
||||||
return Some(value.to_owned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +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.
|
|
||||||
///
|
|
||||||
/// # Normalización
|
|
||||||
///
|
|
||||||
/// - 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 = OptionString::new(" a new string ");
|
|
||||||
/// assert_eq!(s.get(), Some(String::from("a new string")));
|
|
||||||
///
|
|
||||||
/// let empty = OptionString::default();
|
|
||||||
/// assert_eq!(empty.get(), None);
|
|
||||||
/// ```
|
|
||||||
#[derive(AutoDefault, Clone, Debug, Hash, Eq, PartialEq)]
|
|
||||||
pub struct OptionString(Option<String>);
|
|
||||||
|
|
||||||
impl OptionString {
|
|
||||||
/// Crea un nuevo [`OptionString`].
|
|
||||||
///
|
|
||||||
/// El valor se normaliza automáticamente.
|
|
||||||
pub fn new(value: impl AsRef<str>) -> Self {
|
|
||||||
OptionString::default().with_value(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OptionString BUILDER ************************************************************************
|
|
||||||
|
|
||||||
/// Establece una cadena nueva.
|
|
||||||
///
|
|
||||||
/// El valor se normaliza automáticamente.
|
|
||||||
#[builder_fn]
|
|
||||||
pub fn with_value(mut self, value: impl AsRef<str>) -> Self {
|
|
||||||
let value = value.as_ref().trim().to_owned();
|
|
||||||
self.0 = (!value.is_empty()).then_some(value);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
// OptionString GETTERS ************************************************************************
|
|
||||||
|
|
||||||
/// Devuelve la cadena, si existe.
|
|
||||||
pub fn get(&self) -> Option<String> {
|
|
||||||
if let Some(value) = &self.0 {
|
|
||||||
if !value.is_empty() {
|
|
||||||
return Some(value.to_owned());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,8 +7,10 @@ use crate::base::action;
|
||||||
use crate::builder_fn;
|
use crate::builder_fn;
|
||||||
use crate::core::component::{Child, ChildOp, Component};
|
use crate::core::component::{Child, ChildOp, Component};
|
||||||
use crate::core::theme::{ChildrenInRegions, ThemeRef, REGION_CONTENT};
|
use crate::core::theme::{ChildrenInRegions, ThemeRef, REGION_CONTENT};
|
||||||
use crate::html::{html, AssetsOp, Context, Markup, DOCTYPE};
|
use crate::html::{html, Markup, DOCTYPE};
|
||||||
use crate::html::{ClassesOp, OptionClasses, OptionId, OptionTranslated};
|
use crate::html::{AssetsOp, Context};
|
||||||
|
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;
|
||||||
|
|
||||||
|
@ -19,13 +21,13 @@ use crate::service::HttpRequest;
|
||||||
/// renderizado.
|
/// renderizado.
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub struct Page {
|
pub struct Page {
|
||||||
title : OptionTranslated,
|
title : AttrL10n,
|
||||||
description : OptionTranslated,
|
description : AttrL10n,
|
||||||
metadata : Vec<(&'static str, &'static str)>,
|
metadata : Vec<(&'static str, &'static str)>,
|
||||||
properties : Vec<(&'static str, &'static str)>,
|
properties : Vec<(&'static str, &'static str)>,
|
||||||
context : Context,
|
context : Context,
|
||||||
body_id : OptionId,
|
body_id : AttrId,
|
||||||
body_classes: OptionClasses,
|
body_classes: AttrClasses,
|
||||||
regions : ChildrenInRegions,
|
regions : ChildrenInRegions,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,13 +39,13 @@ impl Page {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
pub fn new(request: Option<HttpRequest>) -> Self {
|
pub fn new(request: Option<HttpRequest>) -> Self {
|
||||||
Page {
|
Page {
|
||||||
title : OptionTranslated::default(),
|
title : AttrL10n::default(),
|
||||||
description : OptionTranslated::default(),
|
description : AttrL10n::default(),
|
||||||
metadata : Vec::default(),
|
metadata : Vec::default(),
|
||||||
properties : Vec::default(),
|
properties : Vec::default(),
|
||||||
context : Context::new(request),
|
context : Context::new(request),
|
||||||
body_id : OptionId::default(),
|
body_id : AttrId::default(),
|
||||||
body_classes: OptionClasses::default(),
|
body_classes: AttrClasses::default(),
|
||||||
regions : ChildrenInRegions::default(),
|
regions : ChildrenInRegions::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +115,7 @@ impl Page {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Modifica las clases CSS del elemento `<body>` con una operación sobre [`OptionClasses`].
|
/// Modifica las clases CSS del elemento `<body>` con una operación sobre [`AttrClasses`].
|
||||||
#[builder_fn]
|
#[builder_fn]
|
||||||
pub fn with_body_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
|
pub fn with_body_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
|
||||||
self.body_classes.alter_value(op, classes);
|
self.body_classes.alter_value(op, classes);
|
||||||
|
@ -183,12 +185,12 @@ impl Page {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Devuelve el identificador del elemento `<body>`.
|
/// Devuelve el identificador del elemento `<body>`.
|
||||||
pub fn body_id(&self) -> &OptionId {
|
pub fn body_id(&self) -> &AttrId {
|
||||||
&self.body_id
|
&self.body_id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Devuelve las clases CSS del elemento `<body>`.
|
/// Devuelve las clases CSS del elemento `<body>`.
|
||||||
pub fn body_classes(&self) -> &OptionClasses {
|
pub fn body_classes(&self) -> &AttrClasses {
|
||||||
&self.body_classes
|
&self.body_classes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue