diff --git a/src/base/action.rs b/src/base/action.rs index 977ae9e2..c4f5d27a 100644 --- a/src/base/action.rs +++ b/src/base/action.rs @@ -4,12 +4,26 @@ use crate::prelude::*; /// Tipo de función para manipular componentes y su contexto de renderizado. /// -/// Se usa en acciones definidas en [`component`] y [`theme`] para alterar el comportamiento de los -/// componentes. +/// Se usa en acciones definidas en [`action::component`] y [`action::theme`] para alterar el +/// comportamiento de los componentes. /// /// Recibe referencias mutables (`&mut`) del componente `component` y del contexto `cx`. pub type FnActionWithComponent = fn(component: &mut C, cx: &mut Context); +/// Tipo de función para modificar el [`Markup`] generado por un componente. +/// +/// Se usa en [`action::component::AlterMarkup`] para permitir a las extensiones modificar el HTML +/// final producido por el renderizado de un componente. La edición trabaja a nivel de texto: el +/// [`Markup`] recibido expone su contenido como [`String`], lo que permite aplicar búsquedas, +/// sustituciones, concatenaciones y cualquier otra primitiva de trabajo con cadenas. +/// +/// La función recibe referencias mutables del componente `component` y del contexto `cx`, y toma +/// posesión del `markup` producido hasta ese momento. Devuelve el nuevo [`Markup`] modificado, que +/// se encadena como entrada para la siguiente acción registrada, si la hay. +pub type FnActionAlterMarkup = fn(component: &mut C, cx: &mut Context, markup: Markup) -> Markup; + +// **< Acciones por tipo >************************************************************************** + pub mod component; pub mod theme; diff --git a/src/base/action/component.rs b/src/base/action/component.rs index 30c7ba4a..924f4075 100644 --- a/src/base/action/component.rs +++ b/src/base/action/component.rs @@ -5,3 +5,6 @@ pub use before_render_component::*; mod after_render_component; pub use after_render_component::*; + +mod alter_markup_component; +pub use alter_markup_component::*; diff --git a/src/base/action/component/after_render_component.rs b/src/base/action/component/after_render_component.rs index c4fddffe..0bed68c5 100644 --- a/src/base/action/component/after_render_component.rs +++ b/src/base/action/component/after_render_component.rs @@ -65,6 +65,7 @@ impl AfterRender { ), |action: &Self| (action.f)(component, cx), ); + // Y luego despacha las acciones para el tipo de componente con un identificador dado. if let Some(id) = component.id() { dispatch_actions( diff --git a/src/base/action/component/alter_markup_component.rs b/src/base/action/component/alter_markup_component.rs new file mode 100644 index 00000000..8bddd97a --- /dev/null +++ b/src/base/action/component/alter_markup_component.rs @@ -0,0 +1,93 @@ +use crate::prelude::*; + +use crate::base::action::FnActionAlterMarkup; +use crate::html::html; + +/// Ejecuta [`FnActionAlterMarkup`] para modificar el renderizado de un componente. +pub struct AlterMarkup { + f: FnActionAlterMarkup, + referer_type_id: Option, + referer_id: AttrId, + weight: Weight, +} + +/// Filtro para despachar [`FnActionAlterMarkup`] sobre el renderizado de un componente `C`. +impl ActionDispatcher for AlterMarkup { + /// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`. + fn referer_type_id(&self) -> Option { + self.referer_type_id + } + + /// Devuelve el identificador del componente. + fn referer_id(&self) -> Option { + self.referer_id.get() + } + + /// Devuelve el peso para definir el orden de ejecución. + fn weight(&self) -> Weight { + self.weight + } +} + +impl AlterMarkup { + /// Permite [registrar](Extension::actions) una nueva acción [`FnActionAlterMarkup`]. + pub fn new(f: FnActionAlterMarkup) -> Self { + AlterMarkup { + f, + referer_type_id: Some(UniqueId::of::()), + referer_id: AttrId::default(), + weight: 0, + } + } + + /// Afina el registro para ejecutar la acción [`FnActionAlterMarkup`] 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_id(id); + self + } + + /// Opcional. Acciones con pesos más bajos se aplican antes. Se pueden usar valores negativos. + pub fn with_weight(mut self, value: Weight) -> Self { + self.weight = value; + self + } + + /// Despacha las acciones encadenando el [`Markup`] entre cada una. + #[inline] + pub(crate) fn dispatch(component: &mut C, cx: &mut Context, markup: Markup) -> Markup { + let mut output = markup; + + // Primero despacha las acciones para el tipo de componente. + dispatch_actions( + &ActionKey::new( + UniqueId::of::(), + None, + Some(UniqueId::of::()), + None, + ), + |action: &Self| { + let taken = std::mem::replace(&mut output, html! {}); + output = (action.f)(component, cx, taken); + }, + ); + + // Y luego despacha las acciones para el tipo de componente con un identificador dado. + if let Some(id) = component.id() { + dispatch_actions( + &ActionKey::new( + UniqueId::of::(), + None, + Some(UniqueId::of::()), + Some(id), + ), + |action: &Self| { + let taken = std::mem::replace(&mut output, html! {}); + output = (action.f)(component, cx, taken); + }, + ); + } + + output + } +} diff --git a/src/base/action/component/before_render_component.rs b/src/base/action/component/before_render_component.rs index 7f0b5b57..14f756d4 100644 --- a/src/base/action/component/before_render_component.rs +++ b/src/base/action/component/before_render_component.rs @@ -65,6 +65,7 @@ impl BeforeRender { ), |action: &Self| (action.f)(component, cx), ); + // Y luego despacha las aciones para el tipo de componente con un identificador dado. if let Some(id) = component.id() { dispatch_actions( diff --git a/src/core/action.rs b/src/core/action.rs index 92b3f1aa..de66b296 100644 --- a/src/core/action.rs +++ b/src/core/action.rs @@ -21,7 +21,9 @@ pub use all::dispatch_actions; /// Evita escribir repetidamente `Box::new(...)` para cada acción de la lista, manteniendo el código /// más limpio. /// -/// # Ejemplo +/// # Ejemplos +/// +/// Acciones de tema que ajustan un componente antes y después de renderizarlo: /// /// ```rust,ignore /// impl Extension for MyTheme { @@ -38,6 +40,22 @@ pub use all::dispatch_actions; /// fn before_render_button(c: &mut Button, cx: &mut Context) { todo!() } /// fn after_render_button(c: &mut Button, cx: &mut Context) { todo!() } /// ``` +/// +/// Acción de extensión que transforma el HTML final de un componente mediante edición de texto: +/// +/// ```rust,ignore +/// impl Extension for MyExtension { +/// fn actions(&self) -> Vec { +/// actions_boxed![ +/// action::component::AlterMarkup::