♻️ Define acciones de forma coherente

This commit is contained in:
Manuel Cillero 2023-06-06 20:51:07 +02:00
parent a669608783
commit 163302f4ea
26 changed files with 190 additions and 192 deletions

View file

@ -29,8 +29,8 @@ impl ModuleTrait for Admin {
]
}
fn actions(&self) -> Vec<HookAction> {
vec![hook_action!(BeforeRenderPageHook => before_render_page)]
fn actions(&self) -> Vec<Action> {
vec![action!(ActionBeforeRenderPage => before_render_page)]
}
fn configure_service(&self, cfg: &mut server::web::ServiceConfig) {

View file

@ -153,7 +153,7 @@ impl MegaMenuItem {
define_handle!(COMPONENT_MEGAMENU);
hook_before_render_component!(HOOK_BEFORE_RENDER_MENU, MegaMenu);
action_before_render_component!(ACTION_BEFORE_RENDER_MENU, MegaMenu);
#[rustfmt::skip]
#[derive(Default)]

View file

@ -2,7 +2,7 @@ use pagetop::prelude::*;
define_handle!(COMPONENT_BLOCK);
hook_before_render_component!(HOOK_BEFORE_RENDER_BLOCK, Block);
action_before_render_component!(ACTION_BEFORE_RENDER_BLOCK, Block);
#[rustfmt::skip]
#[derive(Default)]

View file

@ -2,7 +2,7 @@ use pagetop::prelude::*;
define_handle!(COMPONENT_CONTAINER);
hook_before_render_component!(HOOK_BEFORE_RENDER_CONTAINER, Container);
action_before_render_component!(ACTION_BEFORE_RENDER_CONTAINER, Container);
#[derive(Default)]
pub enum ContainerType {

View file

@ -2,7 +2,7 @@ use pagetop::prelude::*;
define_handle!(COMPONENT_FORM);
hook_before_render_component!(HOOK_BEFORE_RENDER_FORM, Form);
action_before_render_component!(ACTION_BEFORE_RENDER_FORM, Form);
#[derive(Default)]
pub enum FormMethod {

View file

@ -2,7 +2,7 @@ use pagetop::prelude::*;
define_handle!(COMPONENT_COLUMN);
hook_before_render_component!(HOOK_BEFORE_RENDER_COLUMN, Column);
action_before_render_component!(ACTION_BEFORE_RENDER_COLUMN, Column);
const SIZE__DEFAULT: &str = "col-md";
const SIZE__1_OF_12: &str = "col-md-1";

View file

@ -4,7 +4,7 @@ use crate::component::grid;
define_handle!(COMPONENT_ROW);
hook_before_render_component!(HOOK_BEFORE_RENDER_ROW, Row);
action_before_render_component!(ACTION_BEFORE_RENDER_ROW, Row);
#[rustfmt::skip]
#[derive(Default)]

View file

@ -26,8 +26,8 @@ impl ModuleTrait for Node {
cfg.route("/node", server::web::get().to(node));
}
fn actions(&self) -> Vec<HookAction> {
vec![hook_action!(BeforeRenderPageHook => before_render_page, -1)]
fn actions(&self) -> Vec<Action> {
vec![action!(ActionBeforeRenderPage => before_render_page, -1)]
}
fn migrations(&self) -> Vec<MigrationItem> {

View file

@ -1,13 +1,13 @@
//! Tipos y funciones esenciales para crear módulos, temas, componentes y acciones.
//! Tipos y funciones esenciales para crear acciones, componentes, módulos y temas.
// API to add new features with modules and themes.
pub mod module;
// API to define functions that alter the behavior of PageTop core.
pub mod action;
// API to build new components.
pub mod component;
// API to define functions that alter the behavior of PageTop core.
pub mod hook;
// API to add new features with modules and themes.
pub mod module;
// Basic theme.
pub(crate) mod basic;

View file

@ -0,0 +1,10 @@
mod definition;
pub use definition::{action_ref, ActionTrait, AnyAction, ACTION_UNNAMED};
mod bundle;
pub use bundle::Action;
use bundle::ActionsBundle;
mod all;
pub(crate) use all::add_action;
pub use all::run_actions;

View file

@ -0,0 +1,28 @@
use crate::core::action::{Action, ActionsBundle};
use crate::{Handle, LazyStatic};
use std::collections::HashMap;
use std::sync::RwLock;
// Registered actions.
static ACTIONS: LazyStatic<RwLock<HashMap<Handle, ActionsBundle>>> =
LazyStatic::new(|| RwLock::new(HashMap::new()));
pub fn add_action(action: Action) {
let mut actions = ACTIONS.write().unwrap();
let action_handle = action.handle();
if let Some(bundle) = actions.get_mut(&action_handle) {
bundle.add(action);
} else {
actions.insert(action_handle, ActionsBundle::new_with(action));
}
}
pub fn run_actions<B, F>(action_handle: Handle, f: F)
where
F: FnMut(&Action) -> B,
{
if let Some(bundle) = ACTIONS.read().unwrap().get(&action_handle) {
bundle.iter_map(f)
}
}

View file

@ -0,0 +1,40 @@
use crate::core::action::ActionTrait;
use std::sync::{Arc, RwLock};
pub type Action = Box<dyn ActionTrait>;
#[macro_export]
macro_rules! action {
( $action:ident => $f:ident $(, $weight:expr)? ) => {{
Box::new($action::new().with_action($f)$(.with_weight($weight))?)
}};
}
pub struct ActionsBundle(Arc<RwLock<Vec<Action>>>);
impl ActionsBundle {
pub fn new() -> Self {
ActionsBundle(Arc::new(RwLock::new(Vec::new())))
}
pub fn new_with(action: Action) -> Self {
let mut bundle = ActionsBundle::new();
bundle.add(action);
bundle
}
pub fn add(&mut self, action: Action) {
let mut bundle = self.0.write().unwrap();
bundle.push(action);
bundle.sort_by_key(|a| a.weight());
}
pub fn iter_map<B, F>(&self, f: F)
where
Self: Sized,
F: FnMut(&Action) -> B,
{
let _: Vec<_> = self.0.read().unwrap().iter().map(f).collect();
}
}

View file

@ -0,0 +1,25 @@
use crate::{define_handle, Handle};
pub use std::any::Any as AnyAction;
define_handle!(ACTION_UNNAMED);
pub trait ActionTrait: AnyAction + Send + Sync {
fn new() -> Self
where
Self: Sized;
fn handle(&self) -> Handle {
ACTION_UNNAMED
}
fn weight(&self) -> isize {
0
}
fn as_ref_any(&self) -> &dyn AnyAction;
}
pub fn action_ref<A: 'static>(action: &dyn ActionTrait) -> &A {
action.as_ref_any().downcast_ref::<A>().unwrap()
}

View file

@ -77,7 +77,7 @@ pub fn component_mut<C: 'static>(component: &mut dyn ComponentTrait) -> &mut C {
}
#[macro_export]
macro_rules! hook_before_render_component {
macro_rules! action_before_render_component {
( $ACTION_HANDLE:ident, $Component:ty ) => {
$crate::paste! {
$crate::define_handle!($ACTION_HANDLE);
@ -89,7 +89,7 @@ macro_rules! hook_before_render_component {
weight: isize,
}
impl HookActionTrait for [< BeforeRender $Component >] {
impl ActionTrait for [< BeforeRender $Component >] {
fn new() -> Self {
[< BeforeRender $Component >] {
action: None,
@ -105,14 +105,14 @@ macro_rules! hook_before_render_component {
self.weight
}
fn as_ref_any(&self) -> &dyn AnyHookAction {
fn as_ref_any(&self) -> &dyn AnyAction {
self
}
}
impl [< BeforeRender $Component >] {
#[allow(dead_code)]
pub fn with_hook(mut self, action: Action) -> Self {
pub fn with_action(mut self, action: Action) -> Self {
self.action = Some(action);
self
}

View file

@ -1,10 +0,0 @@
mod definition;
pub use definition::{action_ref, AnyHookAction, HookActionTrait, HOOK_UNNAMED};
mod holder;
use holder::ActionsHolder;
pub use holder::HookAction;
mod all;
pub(crate) use all::add_action;
pub use all::run_actions;

View file

@ -1,28 +0,0 @@
use super::{ActionsHolder, HookAction};
use crate::{Handle, LazyStatic};
use std::collections::HashMap;
use std::sync::RwLock;
// Registered actions.
static ACTIONS: LazyStatic<RwLock<HashMap<Handle, ActionsHolder>>> =
LazyStatic::new(|| RwLock::new(HashMap::new()));
pub fn add_action(action: HookAction) {
let mut actions = ACTIONS.write().unwrap();
let action_handle = action.handle();
if let Some(holder) = actions.get_mut(&action_handle) {
holder.add(action);
} else {
actions.insert(action_handle, ActionsHolder::new_with(action));
}
}
pub fn run_actions<B, F>(action_handle: Handle, f: F)
where
F: FnMut(&HookAction) -> B,
{
if let Some(holder) = ACTIONS.read().unwrap().get(&action_handle) {
holder.iter_map(f)
}
}

View file

@ -1,25 +0,0 @@
use crate::{define_handle, Handle};
pub use std::any::Any as AnyHookAction;
define_handle!(HOOK_UNNAMED);
pub trait HookActionTrait: AnyHookAction + Send + Sync {
fn new() -> Self
where
Self: Sized;
fn handle(&self) -> Handle {
HOOK_UNNAMED
}
fn weight(&self) -> isize {
0
}
fn as_ref_any(&self) -> &dyn AnyHookAction;
}
pub fn action_ref<A: 'static>(action: &dyn HookActionTrait) -> &A {
action.as_ref_any().downcast_ref::<A>().unwrap()
}

View file

@ -1,40 +0,0 @@
use super::HookActionTrait;
use std::sync::{Arc, RwLock};
pub type HookAction = Box<dyn HookActionTrait>;
#[macro_export]
macro_rules! hook_action {
( $hook:ident => $f:ident $(, $weight:expr)? ) => {{
Box::new($hook::new().with_hook($f)$(.with_weight($weight))?)
}};
}
pub struct ActionsHolder(Arc<RwLock<Vec<HookAction>>>);
impl ActionsHolder {
pub fn new() -> Self {
ActionsHolder(Arc::new(RwLock::new(Vec::new())))
}
pub fn new_with(action: HookAction) -> Self {
let mut holder = ActionsHolder::new();
holder.add(action);
holder
}
pub fn add(&mut self, action: HookAction) {
let mut holder = self.0.write().unwrap();
holder.push(action);
holder.sort_by_key(|a| a.weight());
}
pub fn iter_map<B, F>(&self, f: F)
where
Self: Sized,
F: FnMut(&HookAction) -> B,
{
let _: Vec<_> = self.0.read().unwrap().iter().map(f).collect();
}
}

View file

@ -1,6 +1,5 @@
use super::{ModuleStaticRef, ThemeStaticRef};
use crate::core::hook::add_action;
use crate::core::action::add_action;
use crate::core::module::{ModuleStaticRef, ThemeStaticRef};
use crate::{server, trace, LazyStatic};
#[cfg(feature = "database")]

View file

@ -1,7 +1,6 @@
use super::ThemeStaticRef;
use crate::core::action::Action;
use crate::core::component::L10n;
use crate::core::hook::HookAction;
use crate::core::module::ThemeStaticRef;
use crate::util::single_type_name;
use crate::{define_handle, server, Handle};
@ -42,7 +41,7 @@ pub trait ModuleTrait: BaseModule + Send + Sync {
vec![]
}
fn actions(&self) -> Vec<HookAction> {
fn actions(&self) -> Vec<Action> {
vec![]
}

View file

@ -24,7 +24,7 @@
//!
//! * Acceso unificado y normalizado a base de datos ([`db`]).
//!
//! * Tipos y funciones esenciales para crear módulos, temas, componentes y acciones ([`core`]).
//! * Tipos y funciones esenciales para crear acciones, componentes, módulos y temas ([`core`]).
//!
//! * Tipos de respuestas a peticiones web ([`response`])
//!
@ -72,7 +72,7 @@ pub mod html;
#[cfg(feature = "database")]
pub mod db;
// APIs esenciales para crear módulos, temas, componentes y acciones.
// APIs esenciales para crear acciones, componentes, módulos y temas.
pub mod core;
// API del servidor web.

View file

@ -4,7 +4,7 @@
// Re-exports.
pub use crate::{concat_string, fn_builder, Handle, HashMapResources, LazyStatic, ResultExt};
// Macros declarativas.
// Macros declarativas globales.
pub use crate::{args, define_config, define_handle, define_locale, paste, serve_static_files};
// Funciones útiles.
@ -23,9 +23,9 @@ pub use crate::html::*;
#[cfg(feature = "database")]
pub use crate::{db, db::*, migration_item, pub_migration};
pub use crate::core::{component::*, hook::*, module::*};
pub use crate::core::{action::*, component::*, module::*};
pub use crate::{hook_action, hook_before_render_component};
pub use crate::{action, action_before_render_component};
pub use crate::server;
pub use crate::server::HttpMessage;

View file

@ -1,7 +1,7 @@
pub use actix_web::Result as ResultPage;
mod hook;
pub use hook::{BeforeRenderPageHook, HOOK_BEFORE_RENDER_PAGE};
mod action;
pub use action::{ActionBeforeRenderPage, ACTION_BEFORE_RENDER_PAGE};
mod definition;
pub use definition::Page;

View file

@ -0,0 +1,51 @@
use crate::core::action::{ActionTrait, AnyAction};
use crate::response::page::Page;
use crate::{define_handle, Handle};
define_handle!(ACTION_BEFORE_RENDER_PAGE);
type Action = fn(&mut Page);
pub struct ActionBeforeRenderPage {
action: Option<Action>,
weight: isize,
}
impl ActionTrait for ActionBeforeRenderPage {
fn new() -> Self {
ActionBeforeRenderPage {
action: None,
weight: 0,
}
}
fn handle(&self) -> Handle {
ACTION_BEFORE_RENDER_PAGE
}
fn weight(&self) -> isize {
self.weight
}
fn as_ref_any(&self) -> &dyn AnyAction {
self
}
}
impl ActionBeforeRenderPage {
pub fn with_action(mut self, action: Action) -> Self {
self.action = Some(action);
self
}
pub fn with_weight(mut self, weight: isize) -> Self {
self.weight = weight;
self
}
pub fn run(&self, page: &mut Page) {
if let Some(action) = self.action {
action(page)
}
}
}

View file

@ -1,10 +1,10 @@
use super::{BeforeRenderPageHook, ResultPage, HOOK_BEFORE_RENDER_PAGE};
use crate::core::action::{action_ref, run_actions};
use crate::core::component::*;
use crate::core::hook::{action_ref, run_actions};
use crate::html::{html, Classes, ClassesOp, Favicon, Markup, DOCTYPE};
use crate::locale::{langid_for, LanguageIdentifier};
use crate::response::fatal_error::FatalError;
use crate::response::page::action::{ActionBeforeRenderPage, ACTION_BEFORE_RENDER_PAGE};
use crate::response::page::ResultPage;
use crate::{fn_builder, server};
use unic_langid::CharacterDirection;
@ -164,8 +164,8 @@ impl Page {
pub fn render(&mut self) -> ResultPage<Markup, FatalError> {
// Acciones de los módulos antes de renderizar la página.
run_actions(HOOK_BEFORE_RENDER_PAGE, |hook| {
action_ref::<BeforeRenderPageHook>(&**hook).run(self)
run_actions(ACTION_BEFORE_RENDER_PAGE, |action| {
action_ref::<ActionBeforeRenderPage>(&**action).run(self)
});
// Acciones del tema antes de renderizar la página.

View file

@ -1,51 +0,0 @@
use super::Page;
use crate::core::hook::{AnyHookAction, HookActionTrait};
use crate::{define_handle, Handle};
define_handle!(HOOK_BEFORE_RENDER_PAGE);
type Hook = fn(&mut Page);
pub struct BeforeRenderPageHook {
hook: Option<Hook>,
weight: isize,
}
impl HookActionTrait for BeforeRenderPageHook {
fn new() -> Self {
BeforeRenderPageHook {
hook: None,
weight: 0,
}
}
fn handle(&self) -> Handle {
HOOK_BEFORE_RENDER_PAGE
}
fn weight(&self) -> isize {
self.weight
}
fn as_ref_any(&self) -> &dyn AnyHookAction {
self
}
}
impl BeforeRenderPageHook {
pub fn with_hook(mut self, hook: Hook) -> Self {
self.hook = Some(hook);
self
}
pub fn with_weight(mut self, weight: isize) -> Self {
self.weight = weight;
self
}
pub fn run(&self, page: &mut Page) {
if let Some(hook) = self.hook {
hook(page)
}
}
}