♻️ Define acciones de forma coherente
This commit is contained in:
parent
a669608783
commit
163302f4ea
26 changed files with 190 additions and 192 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
10
pagetop/src/core/action.rs
Normal file
10
pagetop/src/core/action.rs
Normal 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;
|
||||
28
pagetop/src/core/action/all.rs
Normal file
28
pagetop/src/core/action/all.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
40
pagetop/src/core/action/bundle.rs
Normal file
40
pagetop/src/core/action/bundle.rs
Normal 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();
|
||||
}
|
||||
}
|
||||
25
pagetop/src/core/action/definition.rs
Normal file
25
pagetop/src/core/action/definition.rs
Normal 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()
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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![]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
51
pagetop/src/response/page/action.rs
Normal file
51
pagetop/src/response/page/action.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue