Añade hook previo antes de renderizar componentes

This commit is contained in:
Manuel Cillero 2022-07-16 21:16:38 +02:00
parent 166f209dab
commit 616d7ee207
16 changed files with 145 additions and 75 deletions

View file

@ -27,6 +27,7 @@ doc-comment = "0.3.3"
figlet-rs = "0.1.3" figlet-rs = "0.1.3"
futures = "0.3.21" futures = "0.3.21"
once_cell = "1.12.0" once_cell = "1.12.0"
paste = "1.0.7"
substring = "1.4.5" substring = "1.4.5"
term_size = "0.3.2" term_size = "0.3.2"
url = "2.2.2" url = "2.2.2"

View file

@ -2,6 +2,11 @@ use crate::prelude::*;
pub const COMPONENT_BLOCK: &str = "pagetop::component::block"; pub const COMPONENT_BLOCK: &str = "pagetop::component::block";
hook_before_render_component!(
HOOK_BEFORE_RENDER_BLOCK = "pagetop::action::before_render_block",
Block
);
pub struct Block { pub struct Block {
weight : isize, weight : isize,
renderable: Renderable, renderable: Renderable,
@ -37,6 +42,10 @@ impl ComponentTrait for Block {
(self.renderable)(context) (self.renderable)(context)
} }
fn before_render(&mut self, context: &mut InContext) {
before_render_inline(self, context);
}
fn default_render(&self, context: &mut InContext) -> Markup { fn default_render(&self, context: &mut InContext) -> Markup {
let id = context.required_id::<Block>(self.id()); let id = context.required_id::<Block>(self.id());
html! { html! {

View file

@ -2,6 +2,11 @@ use crate::prelude::*;
pub const COMPONENT_CONTAINER: &str = "pagetop::component::container"; pub const COMPONENT_CONTAINER: &str = "pagetop::component::container";
hook_before_render_component!(
HOOK_BEFORE_RENDER_CONTAINER = "pagetop::action::before_render_container",
Container
);
pub enum ContainerType { Header, Footer, Main, Section, Wrapper } pub enum ContainerType { Header, Footer, Main, Section, Wrapper }
pub struct Container { pub struct Container {
@ -41,6 +46,10 @@ impl ComponentTrait for Container {
(self.renderable)(context) (self.renderable)(context)
} }
fn before_render(&mut self, context: &mut InContext) {
before_render_inline(self, context);
}
fn default_render(&self, context: &mut InContext) -> Markup { fn default_render(&self, context: &mut InContext) -> Markup {
match self.container_type() { match self.container_type() {
ContainerType::Header => html! { ContainerType::Header => html! {

View file

@ -2,6 +2,11 @@ use crate::prelude::*;
pub const COMPONENT_FORM: &str = "pagetop::component::form"; pub const COMPONENT_FORM: &str = "pagetop::component::form";
hook_before_render_component!(
HOOK_BEFORE_RENDER_FORM = "pagetop::action::before_render_form",
Form
);
pub enum FormMethod {Get, Post} pub enum FormMethod {Get, Post}
pub struct Form { pub struct Form {
@ -43,6 +48,10 @@ impl ComponentTrait for Form {
(self.renderable)(context) (self.renderable)(context)
} }
fn before_render(&mut self, context: &mut InContext) {
before_render_inline(self, context);
}
fn default_render(&self, context: &mut InContext) -> Markup { fn default_render(&self, context: &mut InContext) -> Markup {
let method = match self.method() { let method = match self.method() {
FormMethod::Get => None, FormMethod::Get => None,

View file

@ -2,6 +2,11 @@ use crate::prelude::*;
pub const COMPONENT_COLUMN: &str = "pagetop::component::grid::column"; pub const COMPONENT_COLUMN: &str = "pagetop::component::grid::column";
hook_before_render_component!(
HOOK_BEFORE_RENDER_COLUMN = "pagetop::action::before_render_column",
Column
);
const SIZE_DEFAULT: &str = "col-md"; const SIZE_DEFAULT: &str = "col-md";
const SIZE_1_OF_12: &str = "col-md-1"; const SIZE_1_OF_12: &str = "col-md-1";
const SIZE_2_OF_12: &str = "col-md-2"; const SIZE_2_OF_12: &str = "col-md-2";
@ -66,6 +71,10 @@ impl ComponentTrait for Column {
(self.renderable)(context) (self.renderable)(context)
} }
fn before_render(&mut self, context: &mut InContext) {
before_render_inline(self, context);
}
fn default_render(&self, context: &mut InContext) -> Markup { fn default_render(&self, context: &mut InContext) -> Markup {
html! { html! {
div id=[self.id().get()] class=[self.classes().get()] { div id=[self.id().get()] class=[self.classes().get()] {

View file

@ -2,6 +2,11 @@ use crate::prelude::*;
pub const COMPONENT_ROW: &str = "pagetop::component::grid::row"; pub const COMPONENT_ROW: &str = "pagetop::component::grid::row";
hook_before_render_component!(
HOOK_BEFORE_RENDER_ROW = "pagetop::action::before_render_row",
Row
);
pub struct Row { pub struct Row {
weight : isize, weight : isize,
renderable: Renderable, renderable: Renderable,
@ -35,6 +40,10 @@ impl ComponentTrait for Row {
(self.renderable)(context) (self.renderable)(context)
} }
fn before_render(&mut self, context: &mut InContext) {
before_render_inline(self, context);
}
fn default_render(&self, context: &mut InContext) -> Markup { fn default_render(&self, context: &mut InContext) -> Markup {
html! { html! {
div id=[self.id().get()] class=[self.classes().get()] { div id=[self.id().get()] class=[self.classes().get()] {

View file

@ -1,6 +1,5 @@
use crate::prelude::*; use crate::prelude::*;
pub const COMPONENT_MENU: &str = "pagetop::component::menu";
pub const COMPONENT_MENUITEM: &str = "pagetop::component::menu_item"; pub const COMPONENT_MENUITEM: &str = "pagetop::component::menu_item";
pub enum MenuItemType { pub enum MenuItemType {
@ -173,6 +172,13 @@ impl MenuItem {
// Menu. // Menu.
pub const COMPONENT_MENU: &str = "pagetop::component::menu";
hook_before_render_component!(
HOOK_BEFORE_RENDER_MENU = "pagetop::action::before_render_menu",
Menu
);
pub struct Menu { pub struct Menu {
weight : isize, weight : isize,
renderable: Renderable, renderable: Renderable,
@ -206,6 +212,10 @@ impl ComponentTrait for Menu {
(self.renderable)(context) (self.renderable)(context)
} }
fn before_render(&mut self, context: &mut InContext) {
before_render_inline(self, context);
}
fn default_render(&self, context: &mut InContext) -> Markup { fn default_render(&self, context: &mut InContext) -> Markup {
context context
.alter(InContextOp::StyleSheet(AssetsOp::Add( .alter(InContextOp::StyleSheet(AssetsOp::Add(

View file

@ -1,9 +1,3 @@
mod hook;
pub use hook::{
HOOK_BEFORE_RENDER_COMPONENT,
BeforeRenderComponentHook,
};
mod context; mod context;
pub use context::{InContext, InContextOp}; pub use context::{InContext, InContextOp};

View file

@ -1,7 +1,6 @@
use crate::util; use crate::util;
use crate::html::{Markup, html}; use crate::html::{Markup, html};
use crate::core::hook::{hook_ref, run_hooks}; use super::InContext;
use super::{HOOK_BEFORE_RENDER_COMPONENT, BeforeRenderComponentHook, InContext};
pub use std::any::Any as AnyComponent; pub use std::any::Any as AnyComponent;
@ -50,11 +49,8 @@ pub fn component_mut<C: 'static>(component: &mut dyn ComponentTrait) -> &mut C {
} }
pub fn render_component(component: &mut dyn ComponentTrait, context: &mut InContext) -> Markup { pub fn render_component(component: &mut dyn ComponentTrait, context: &mut InContext) -> Markup {
// Acciones de los módulos antes de renderizar el componente. // Acciones del componente antes de renderizar.
run_hooks( component.before_render(context);
HOOK_BEFORE_RENDER_COMPONENT,
|hook| hook_ref::<BeforeRenderComponentHook>(&**hook).run(component, context)
);
// Acciones del tema antes de renderizar el componente. // Acciones del tema antes de renderizar el componente.
context.theme().before_render_component(component, context); context.theme().before_render_component(component, context);
@ -67,3 +63,68 @@ pub fn render_component(component: &mut dyn ComponentTrait, context: &mut InCont
false => html! {} false => html! {}
} }
} }
#[macro_export]
macro_rules! hook_before_render_component {
( $ACTION_HANDLER:ident = $handler:literal, $Component:ty ) => {
paste::paste! {
const $ACTION_HANDLER: &str = $handler;
type Action = fn(&$Component, &mut InContext);
pub struct [< BeforeRender $Component >] {
action: Option<Action>,
weight: isize,
}
impl HookTrait for [< BeforeRender $Component >] {
fn new() -> Self {
[< BeforeRender $Component >] {
action: None,
weight: 0,
}
}
fn handler(&self) -> &'static str {
$ACTION_HANDLER
}
fn weight(&self) -> isize {
self.weight
}
fn as_ref_any(&self) -> &dyn AnyHook {
self
}
}
impl [< BeforeRender $Component >] {
#[allow(dead_code)]
pub fn with_hook(mut self, action: Action) -> Self {
self.action = Some(action);
self
}
#[allow(dead_code)]
pub fn with_weight(mut self, weight: isize) -> Self {
self.weight = weight;
self
}
pub fn run(&self, component: &mut $Component, context: &mut InContext) {
if let Some(action) = self.action {
action(component, context)
}
}
}
#[inline(always)]
fn before_render_inline(component: &mut $Component, context: &mut InContext) {
run_actions(
$ACTION_HANDLER,
|action| action_ref::<[< BeforeRender $Component >]>(&**action).run(component, context)
);
}
}
};
}

View file

@ -1,48 +0,0 @@
use crate::core::hook::{HookTrait, AnyHook};
use super::{ComponentTrait, InContext};
pub const HOOK_BEFORE_RENDER_COMPONENT: &str = "pagetop::hook::before_render_component";
pub struct BeforeRenderComponentHook {
hook: Option<fn(&mut dyn ComponentTrait, &mut InContext)>,
weight: isize,
}
impl HookTrait for BeforeRenderComponentHook {
fn new() -> Self {
BeforeRenderComponentHook {
hook: None,
weight: 0,
}
}
fn handler(&self) -> &'static str {
HOOK_BEFORE_RENDER_COMPONENT
}
fn weight(&self) -> isize {
self.weight
}
fn as_ref_any(&self) -> &dyn AnyHook {
self
}
}
impl BeforeRenderComponentHook {
pub fn with_hook(mut self, hook: fn(&mut dyn ComponentTrait, &mut InContext)) -> Self {
self.hook = Some(hook);
self
}
pub fn with_weight(mut self, weight: isize) -> Self {
self.weight = weight;
self
}
pub fn run(&self, component: &mut dyn ComponentTrait, context: &mut InContext) {
if let Some(hook) = self.hook {
hook(component, context)
}
}
}

View file

@ -1,8 +1,8 @@
mod definition; mod definition;
pub use definition::{ pub use definition::{
HookTrait,
AnyHook, AnyHook,
hook_ref, HookTrait,
action_ref,
}; };
mod holder; mod holder;
@ -10,5 +10,5 @@ pub use holder::HookAction;
use holder::HooksHolder; use holder::HooksHolder;
mod all; mod all;
pub use all::run_hooks; pub use all::run_actions;
pub(crate) use all::add_hook; pub(crate) use all::add_hook;

View file

@ -19,7 +19,7 @@ pub fn add_hook(hook: HookAction) {
} }
} }
pub fn run_hooks<B, F>(action_handler: &str, f: F) where F: FnMut(&HookAction) -> B { pub fn run_actions<B, F>(action_handler: &str, f: F) where F: FnMut(&HookAction) -> B {
if let Some(actions) = ACTIONS.read().unwrap().get(action_handler) { if let Some(actions) = ACTIONS.read().unwrap().get(action_handler) {
actions.iter_map(f) actions.iter_map(f)
} }

View file

@ -12,6 +12,6 @@ pub trait HookTrait: AnyHook + Send + Sync {
fn as_ref_any(&self) -> &dyn AnyHook; fn as_ref_any(&self) -> &dyn AnyHook;
} }
pub fn hook_ref<A: 'static>(hook: &dyn HookTrait) -> &A { pub fn action_ref<A: 'static>(hook: &dyn HookTrait) -> &A {
hook.as_ref_any().downcast_ref::<A>().unwrap() hook.as_ref_any().downcast_ref::<A>().unwrap()
} }

View file

@ -1,6 +1,6 @@
//! Re-exporta recursos comunes. //! Re-exporta recursos comunes.
// Macros, globals and helpers. // Global macros and helpers.
pub use crate::{ pub use crate::{
args, args,
concat_string, concat_string,
@ -25,12 +25,17 @@ pub use crate::app;
pub use crate::app::AppTrait; pub use crate::app::AppTrait;
pub use crate::app::application::Application; pub use crate::app::application::Application;
pub use crate::{hook_action, core::{ pub use crate::core::{
component::*, component::*,
hook::*, hook::*,
module::*, module::*,
theme::*, theme::*,
}}; };
pub use crate::{
hook_action,
hook_before_render_component,
};
pub use crate::response::page::*; pub use crate::response::page::*;

View file

@ -1,7 +1,7 @@
use crate::{Lazy, app, trace}; use crate::{Lazy, app, trace};
use crate::config::SETTINGS; use crate::config::SETTINGS;
use crate::html::*; use crate::html::*;
use crate::core::hook::{hook_ref, run_hooks}; use crate::core::hook::{action_ref, run_actions};
use crate::core::component::*; use crate::core::component::*;
use super::{HOOK_BEFORE_RENDER_PAGE, BeforeRenderPageHook}; use super::{HOOK_BEFORE_RENDER_PAGE, BeforeRenderPageHook};
@ -193,9 +193,9 @@ impl Page {
pub fn render(&mut self) -> app::Result<Markup> { pub fn render(&mut self) -> app::Result<Markup> {
// Acciones de los módulos antes de renderizar la página. // Acciones de los módulos antes de renderizar la página.
run_hooks( run_actions(
HOOK_BEFORE_RENDER_PAGE, HOOK_BEFORE_RENDER_PAGE,
|hook| hook_ref::<BeforeRenderPageHook>(&**hook).run(self) |hook| action_ref::<BeforeRenderPageHook>(&**hook).run(self)
); );
// Acciones del tema antes de renderizar la página. // Acciones del tema antes de renderizar la página.

View file

@ -3,8 +3,10 @@ use super::Page;
pub const HOOK_BEFORE_RENDER_PAGE: &str = "pagetop::hook::before_render_page"; pub const HOOK_BEFORE_RENDER_PAGE: &str = "pagetop::hook::before_render_page";
type Hook = fn(&mut Page);
pub struct BeforeRenderPageHook { pub struct BeforeRenderPageHook {
hook: Option<fn(&mut Page)>, hook: Option<Hook>,
weight: isize, weight: isize,
} }
@ -30,7 +32,7 @@ impl HookTrait for BeforeRenderPageHook {
} }
impl BeforeRenderPageHook { impl BeforeRenderPageHook {
pub fn with_hook(mut self, hook: fn(&mut Page)) -> Self { pub fn with_hook(mut self, hook: Hook) -> Self {
self.hook = Some(hook); self.hook = Some(hook);
self self
} }