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"
futures = "0.3.21"
once_cell = "1.12.0"
paste = "1.0.7"
substring = "1.4.5"
term_size = "0.3.2"
url = "2.2.2"

View file

@ -2,6 +2,11 @@ use crate::prelude::*;
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 {
weight : isize,
renderable: Renderable,
@ -37,6 +42,10 @@ impl ComponentTrait for Block {
(self.renderable)(context)
}
fn before_render(&mut self, context: &mut InContext) {
before_render_inline(self, context);
}
fn default_render(&self, context: &mut InContext) -> Markup {
let id = context.required_id::<Block>(self.id());
html! {

View file

@ -2,6 +2,11 @@ use crate::prelude::*;
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 struct Container {
@ -41,6 +46,10 @@ impl ComponentTrait for Container {
(self.renderable)(context)
}
fn before_render(&mut self, context: &mut InContext) {
before_render_inline(self, context);
}
fn default_render(&self, context: &mut InContext) -> Markup {
match self.container_type() {
ContainerType::Header => html! {

View file

@ -2,6 +2,11 @@ use crate::prelude::*;
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 struct Form {
@ -43,6 +48,10 @@ impl ComponentTrait for Form {
(self.renderable)(context)
}
fn before_render(&mut self, context: &mut InContext) {
before_render_inline(self, context);
}
fn default_render(&self, context: &mut InContext) -> Markup {
let method = match self.method() {
FormMethod::Get => None,

View file

@ -2,6 +2,11 @@ use crate::prelude::*;
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_1_OF_12: &str = "col-md-1";
const SIZE_2_OF_12: &str = "col-md-2";
@ -66,6 +71,10 @@ impl ComponentTrait for Column {
(self.renderable)(context)
}
fn before_render(&mut self, context: &mut InContext) {
before_render_inline(self, context);
}
fn default_render(&self, context: &mut InContext) -> Markup {
html! {
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";
hook_before_render_component!(
HOOK_BEFORE_RENDER_ROW = "pagetop::action::before_render_row",
Row
);
pub struct Row {
weight : isize,
renderable: Renderable,
@ -35,6 +40,10 @@ impl ComponentTrait for Row {
(self.renderable)(context)
}
fn before_render(&mut self, context: &mut InContext) {
before_render_inline(self, context);
}
fn default_render(&self, context: &mut InContext) -> Markup {
html! {
div id=[self.id().get()] class=[self.classes().get()] {

View file

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

View file

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

View file

@ -1,7 +1,6 @@
use crate::util;
use crate::html::{Markup, html};
use crate::core::hook::{hook_ref, run_hooks};
use super::{HOOK_BEFORE_RENDER_COMPONENT, BeforeRenderComponentHook, InContext};
use super::InContext;
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 {
// Acciones de los módulos antes de renderizar el componente.
run_hooks(
HOOK_BEFORE_RENDER_COMPONENT,
|hook| hook_ref::<BeforeRenderComponentHook>(&**hook).run(component, context)
);
// Acciones del componente antes de renderizar.
component.before_render(context);
// Acciones del tema antes de renderizar el componente.
context.theme().before_render_component(component, context);
@ -67,3 +63,68 @@ pub fn render_component(component: &mut dyn ComponentTrait, context: &mut InCont
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;
pub use definition::{
HookTrait,
AnyHook,
hook_ref,
HookTrait,
action_ref,
};
mod holder;
@ -10,5 +10,5 @@ pub use holder::HookAction;
use holder::HooksHolder;
mod all;
pub use all::run_hooks;
pub use all::run_actions;
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) {
actions.iter_map(f)
}

View file

@ -12,6 +12,6 @@ pub trait HookTrait: AnyHook + Send + Sync {
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()
}

View file

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

View file

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

View file

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