🚧 Working on actions

This commit is contained in:
Manuel Cillero 2024-03-27 07:12:42 +01:00
parent e732244a2e
commit d99a5aa586
23 changed files with 480 additions and 323 deletions

View file

@ -1,10 +1,19 @@
mod definition;
pub use definition::ActionTrait;
pub use definition::{ActionBase, ActionBox, ActionKey, ActionTrait};
mod list;
pub use list::Action;
use list::ActionsList;
mod all;
pub(crate) use all::add_action;
pub use all::{dispatch_actions, KeyAction};
pub use all::dispatch_actions;
#[macro_export]
macro_rules! actions {
() => {
Vec::<ActionBox>::new()
};
( $($action:expr),+ $(,)? ) => {{
vec![$(Box::new($action),)+]
}};
}

View file

@ -1,35 +1,31 @@
use crate::core::action::{Action, ActionTrait, ActionsList};
use crate::{LazyStatic, TypeId};
use crate::core::action::{ActionBox, ActionKey, ActionTrait, ActionsList};
use crate::LazyStatic;
use std::collections::HashMap;
use std::sync::RwLock;
pub type KeyAction = (TypeId, Option<TypeId>, Option<String>);
// Registered actions.
static ACTIONS: LazyStatic<RwLock<HashMap<KeyAction, ActionsList>>> =
static ACTIONS: LazyStatic<RwLock<HashMap<ActionKey, ActionsList>>> =
LazyStatic::new(|| RwLock::new(HashMap::new()));
pub fn add_action(action: Action) {
pub fn add_action(action: ActionBox) {
let key = action.key();
let mut actions = ACTIONS.write().unwrap();
let key_action = (
action.type_id(),
action.referer_type_id(),
action.referer_id(),
);
if let Some(list) = actions.get_mut(&key_action) {
if let Some(list) = actions.get_mut(&key) {
list.add(action);
} else {
actions.insert(key_action, ActionsList::new(action));
let mut list = ActionsList::new();
list.add(action);
actions.insert(key, list);
}
}
pub fn dispatch_actions<A, B, F>(key_action: KeyAction, f: F)
pub fn dispatch_actions<A, B, F>(key: ActionKey, f: F)
where
A: ActionTrait,
F: FnMut(&A) -> B,
{
if let Some(list) = ACTIONS.read().unwrap().get(&key_action) {
if let Some(list) = ACTIONS.read().unwrap().get(&key) {
list.iter_map(f)
}
}

View file

@ -1,7 +1,41 @@
use crate::core::AnyBase;
use crate::{TypeId, Weight};
pub trait ActionTrait: AnyBase + Send + Sync {
pub type ActionBox = Box<dyn ActionTrait>;
#[derive(Eq, PartialEq, Hash)]
pub struct ActionKey {
action_type_id: TypeId,
theme_type_id: Option<TypeId>,
referer_type_id: Option<TypeId>,
referer_id: Option<String>,
}
impl ActionKey {
pub fn new(
action_type_id: TypeId,
theme_type_id: Option<TypeId>,
referer_type_id: Option<TypeId>,
referer_id: Option<String>,
) -> Self {
ActionKey {
action_type_id,
theme_type_id,
referer_type_id,
referer_id,
}
}
}
pub trait ActionBase {
fn key(&self) -> ActionKey;
}
pub trait ActionTrait: ActionBase + AnyBase + Send + Sync {
fn theme_type_id(&self) -> Option<TypeId> {
None
}
fn referer_type_id(&self) -> Option<TypeId> {
None
}
@ -14,3 +48,14 @@ pub trait ActionTrait: AnyBase + Send + Sync {
0
}
}
impl<A: ActionTrait> ActionBase for A {
fn key(&self) -> ActionKey {
ActionKey {
action_type_id: self.type_id(),
theme_type_id: self.theme_type_id(),
referer_type_id: self.referer_type_id(),
referer_id: self.referer_id(),
}
}
}

View file

@ -1,23 +1,19 @@
use crate::core::action::ActionTrait;
use crate::core::action::{ActionBox, ActionTrait};
use crate::core::AnyTo;
use crate::trace;
use crate::AutoDefault;
use std::sync::{Arc, RwLock};
pub type Action = Box<dyn ActionTrait>;
use std::sync::RwLock;
#[derive(AutoDefault)]
pub struct ActionsList(Arc<RwLock<Vec<Action>>>);
pub struct ActionsList(RwLock<Vec<ActionBox>>);
impl ActionsList {
pub fn new(action: Action) -> Self {
let mut list = ActionsList::default();
list.add(action);
list
pub fn new() -> Self {
ActionsList::default()
}
pub fn add(&mut self, action: Action) {
pub fn add(&mut self, action: ActionBox) {
let mut list = self.0.write().unwrap();
list.push(action);
list.sort_by_key(|a| a.weight());
@ -35,26 +31,12 @@ impl ActionsList {
.unwrap()
.iter()
.map(|a| {
if let Some(action) = (&**a).downcast_ref::<A>() {
if let Some(action) = (**a).downcast_ref::<A>() {
f(action);
} else {
trace::error!("Failed to downcast action of type {}", (&**a).type_name());
trace::error!("Failed to downcast action of type {}", (**a).type_name());
}
})
.collect();
}
}
#[macro_export]
macro_rules! actions {
() => {
Vec::<Action>::new()
};
( $($action:expr),+ $(,)? ) => {{
let mut v = Vec::<Action>::new();
$(
v.push(Box::new($action));
)*
v
}};
}

View file

@ -50,16 +50,14 @@ impl<C: ComponentTrait> ComponentBase for C {
self.setup_before_prepare(cx);
// Acciones del tema antes de preparar el componente.
cx.theme().before_prepare_component(self, cx);
action::theme::BeforePrepare::dispatch(self, cx);
// Acciones de los módulos antes de preparar el componente.
action::component::BeforePrepareComponent::dispatch(self, cx, None);
if let Some(id) = self.id() {
action::component::BeforePrepareComponent::dispatch(self, cx, Some(id));
}
action::component::BeforePrepare::dispatch(self, cx);
action::component::BeforePrepare::dispatch_by_id(self, cx);
// Renderiza el componente.
let markup = match cx.theme().render_component(self, cx) {
let markup = match action::theme::RenderComponent::dispatch(self, cx) {
Some(html) => html,
None => match self.prepare_component(cx) {
PrepareMarkup::None => html! {},
@ -69,13 +67,11 @@ impl<C: ComponentTrait> ComponentBase for C {
};
// Acciones del tema después de preparar el componente.
cx.theme().after_prepare_component(self, cx);
action::theme::AfterPrepare::dispatch(self, cx);
// Acciones de los módulos después de preparar el componente.
action::component::AfterPrepareComponent::dispatch(self, cx, None);
if let Some(id) = self.id() {
action::component::AfterPrepareComponent::dispatch(self, cx, Some(id));
}
action::component::AfterPrepare::dispatch(self, cx);
action::component::AfterPrepare::dispatch_by_id(self, cx);
markup
} else {

View file

@ -1,4 +1,4 @@
use crate::core::action::Action;
use crate::core::action::ActionBox;
use crate::core::theme::ThemeRef;
use crate::core::AnyBase;
use crate::locale::L10n;
@ -31,7 +31,7 @@ pub trait PackageTrait: AnyBase + Send + Sync {
vec![]
}
fn actions(&self) -> Vec<Action> {
fn actions(&self) -> Vec<ActionBox> {
actions![]
}

View file

@ -1,5 +1,5 @@
use crate::base::component::Layout;
use crate::core::component::{ComponentBase, ComponentTrait, Context};
use crate::core::component::{ComponentBase, ComponentTrait};
use crate::core::package::PackageTrait;
use crate::html::{html, Favicon, Markup};
use crate::locale::L10n;
@ -26,13 +26,13 @@ pub trait ThemeTrait: PackageTrait + Send + Sync {
fn before_prepare_body(&self, page: &mut Page) {}
fn prepare_body(&self, page: &mut Page) -> Markup {
let skip_to = concat_string!("#", page.skip_to().get().unwrap_or("content".to_owned()));
let skip_to_id = concat_string!("#", page.skip_to().get().unwrap_or("content".to_owned()));
html! {
body id=[page.body_id().get()] class=[page.body_classes().get()] {
@if let Some(skip) = L10n::l("skip_to_content").using(page.context().langid()) {
div class="skip__to_content" {
a href=(skip_to) { (skip) }
a href=(skip_to_id) { (skip) }
}
}
(Layout::new().render(page.context()))
@ -80,66 +80,4 @@ pub trait ThemeTrait: PackageTrait + Send + Sync {
}
}
}
#[rustfmt::skip]
#[allow(unused_variables)]
fn before_prepare_component(
&self,
component: &mut dyn ComponentTrait,
cx: &mut Context,
) {
/*
Cómo usarlo:
match component.type_id() {
t if t == TypeId::of::<Block>() => {
if let Some(b) = component.downcast_mut::<Block>() {
b.alter_title("New title");
}
},
_ => {},
}
*/
}
#[rustfmt::skip]
#[allow(unused_variables)]
fn after_prepare_component(
&self,
component: &mut dyn ComponentTrait,
cx: &mut Context,
) {
/*
Cómo usarlo:
match component.type_id() {
t if t == TypeId::of::<Block>() => {
if let Some(b) = component.downcast_mut::<Block>() {
b.alter_title("New title");
}
},
_ => {},
}
*/
}
#[rustfmt::skip]
#[allow(unused_variables)]
fn render_component(
&self,
component: &dyn ComponentTrait,
cx: &mut Context,
) -> Option<Markup> {
None
/*
Cómo usarlo:
match component.type_id() {
t if t == TypeId::of::<Block>() => {
Some(block_default(block))
},
_ => None,
}
*/
}
}