🎨 Las acciones pasan a la estructura base

This commit is contained in:
Manuel Cillero 2023-06-28 00:22:56 +02:00
parent 7bd4243947
commit 50abc73d8a
27 changed files with 275 additions and 251 deletions

View file

@ -1,5 +1,5 @@
pub mod action;
pub mod actions;
pub mod component;
pub mod components;
pub mod theme;
pub mod themes;

View file

@ -1,3 +1,7 @@
mod before_prepare_component;
mod after_prepare_component;
pub mod block;
pub mod page;

View file

@ -4,10 +4,10 @@ macro_rules! action_after_prepare_component {
$crate::paste! {
$crate::use_handle!($ACTION_HANDLE);
type Action = fn(&$Component, &mut RenderContext);
pub type ActionAfter = fn(component: &$Component, rcx: &mut RenderContext);
pub struct [<AfterPrepare $Component>] {
action: Option<Action>,
action: Option<ActionAfter>,
weight: isize,
}
@ -34,7 +34,7 @@ macro_rules! action_after_prepare_component {
impl [<AfterPrepare $Component>] {
#[allow(dead_code)]
pub fn with_action(mut self, action: Action) -> Self {
pub fn with_action(mut self, action: ActionAfter) -> Self {
self.action = Some(action);
self
}

View file

@ -4,10 +4,10 @@ macro_rules! action_before_prepare_component {
$crate::paste! {
$crate::use_handle!($ACTION_HANDLE);
type Action = fn(&$Component, &mut RenderContext);
pub type ActionBefore = fn(component: &$Component, rcx: &mut RenderContext);
pub struct [<BeforePrepare $Component>] {
action: Option<Action>,
action: Option<ActionBefore>,
weight: isize,
}
@ -34,7 +34,7 @@ macro_rules! action_before_prepare_component {
impl [<BeforePrepare $Component>] {
#[allow(dead_code)]
pub fn with_action(mut self, action: Action) -> Self {
pub fn with_action(mut self, action: ActionBefore) -> Self {
self.action = Some(action);
self
}

View file

@ -0,0 +1,8 @@
use crate::prelude::*;
action_before_prepare_component!(
ACTION_BEFORE_PREPARE_BLOCK for Block
);
action_after_prepare_component!(
ACTION_AFTER_PREPARE_BLOCK for Block
);

View file

@ -0,0 +1,13 @@
use crate::prelude::*;
pub type ActionPage = fn(page: &mut Page);
mod before_prepare_page;
pub use before_prepare_page::{
run_actions_before_prepare_page, ActionBeforePreparePage, ACTION_BEFORE_PREPARE_PAGE,
};
mod before_render_page;
pub use before_render_page::{
run_actions_before_render_page, ActionBeforeRenderPage, ACTION_BEFORE_RENDER_PAGE,
};

View file

@ -1,13 +1,11 @@
use crate::core::action::{ActionTrait, AnyAction};
use crate::response::page::Page;
use crate::{use_handle, Handle};
use crate::prelude::*;
use super::ActionPage;
use_handle!(ACTION_BEFORE_PREPARE_PAGE);
type Action = fn(&mut Page);
pub struct ActionBeforePreparePage {
action: Option<Action>,
action: Option<ActionPage>,
weight: isize,
}
@ -33,7 +31,7 @@ impl ActionTrait for ActionBeforePreparePage {
}
impl ActionBeforePreparePage {
pub fn with_action(mut self, action: Action) -> Self {
pub fn with_action(mut self, action: ActionPage) -> Self {
self.action = Some(action);
self
}
@ -49,3 +47,10 @@ impl ActionBeforePreparePage {
}
}
}
#[inline(always)]
pub fn run_actions_before_prepare_page(page: &mut Page) {
run_actions(ACTION_BEFORE_PREPARE_PAGE, |action| {
action_ref::<ActionBeforePreparePage>(&**action).run(page)
});
}

View file

@ -1,13 +1,11 @@
use crate::core::action::{ActionTrait, AnyAction};
use crate::response::page::Page;
use crate::{use_handle, Handle};
use crate::prelude::*;
use super::ActionPage;
use_handle!(ACTION_BEFORE_RENDER_PAGE);
type Action = fn(&mut Page);
pub struct ActionBeforeRenderPage {
action: Option<Action>,
action: Option<ActionPage>,
weight: isize,
}
@ -33,7 +31,7 @@ impl ActionTrait for ActionBeforeRenderPage {
}
impl ActionBeforeRenderPage {
pub fn with_action(mut self, action: Action) -> Self {
pub fn with_action(mut self, action: ActionPage) -> Self {
self.action = Some(action);
self
}
@ -49,3 +47,10 @@ impl ActionBeforeRenderPage {
}
}
}
#[inline(always)]
pub fn run_actions_before_render_page(page: &mut Page) {
run_actions(ACTION_BEFORE_RENDER_PAGE, |action| {
action_ref::<ActionBeforeRenderPage>(&**action).run(page)
});
}

View file

@ -2,8 +2,6 @@ use crate::prelude::*;
use_handle!(COMPONENT_BLOCK);
action_before_prepare_component!(ACTION_BEFORE_PREPARE_BLOCK for Block);
#[rustfmt::skip]
#[derive(Default)]
pub struct Block {
@ -38,7 +36,7 @@ impl ComponentTrait for Block {
}
fn before_prepare_component(&mut self, rcx: &mut RenderContext) {
run_actions_before_prepare_component(self, rcx);
actions::block::run_actions_before_prepare_component(self, rcx);
}
fn prepare_component(&self, rcx: &mut RenderContext) -> PrepareMarkup {
@ -55,6 +53,10 @@ impl ComponentTrait for Block {
})
}
fn after_prepare_component(&mut self, rcx: &mut RenderContext) {
actions::block::run_actions_after_prepare_component(self, rcx);
}
fn as_ref_any(&self) -> &dyn AnyComponent {
self
}

View file

@ -1,2 +0,0 @@
mod basic;
pub(crate) use basic::Basic;

View file

@ -0,0 +1,2 @@
mod basic;
pub use basic::Basic;

View file

@ -11,8 +11,8 @@ static ACTIONS: LazyStatic<RwLock<HashMap<Handle, ActionsList>>> =
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);
if let Some(list) = actions.get_mut(&action_handle) {
list.add(action);
} else {
actions.insert(action_handle, ActionsList::new_with(action));
}
@ -22,7 +22,7 @@ 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)
if let Some(list) = ACTIONS.read().unwrap().get(&action_handle) {
list.iter_map(f)
}
}

View file

@ -6,8 +6,8 @@ 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))?)
( $action:ty => $f:ident $(, $weight:expr)? ) => {{
Box::new(<$action>::new().with_action($f)$(.with_weight($weight))?)
}};
}
@ -19,15 +19,15 @@ impl ActionsList {
}
pub fn new_with(action: Action) -> Self {
let mut bundle = ActionsList::new();
bundle.add(action);
bundle
let mut list = ActionsList::new();
list.add(action);
list
}
pub fn add(&mut self, action: Action) {
let mut bundle = self.0.write().unwrap();
bundle.push(action);
bundle.sort_by_key(|a| a.weight());
let mut list = self.0.write().unwrap();
list.push(action);
list.sort_by_key(|a| a.weight());
}
pub fn iter_map<B, F>(&self, f: F)

View file

@ -10,7 +10,7 @@ use std::str::FromStr;
static THEME: LazyStatic<ThemeStaticRef> =
LazyStatic::new(|| match theme_by_single_name(&config::SETTINGS.app.theme) {
Some(theme) => theme,
None => &crate::base::theme::Basic,
None => &crate::base::themes::Basic,
});
pub enum ContextOp {

View file

@ -25,9 +25,9 @@ impl PackComponents {
}
pub fn new_with(component: impl ComponentTrait) -> Self {
let mut bundle = PackComponents::new();
bundle.alter_pack(PackOp::Add, component);
bundle
let mut pack = PackComponents::new();
pack.alter_pack(PackOp::Add, component);
pack
}
pub(crate) fn merge(one: Option<&PackComponents>, other: Option<&PackComponents>) -> Self {

View file

@ -28,7 +28,7 @@ pub fn register_modules(app: ModuleStaticRef) {
let mut list: Vec<ModuleStaticRef> = Vec::new();
// Enable basic theme.
add_to_enabled(&mut list, &crate::base::theme::Basic);
add_to_enabled(&mut list, &crate::base::themes::Basic);
// Enable application modules.
add_to_enabled(&mut list, app);

View file

@ -1,4 +1,4 @@
use crate::base::component::L10n;
use crate::base::components::L10n;
use crate::core::action::Action;
use crate::core::theme::ThemeStaticRef;
use crate::{service, util, Handle};

View file

@ -1,4 +1,4 @@
use crate::base::component::L10n;
use crate::base::components::L10n;
use crate::core::component::{ComponentTrait, RenderContext};
use crate::core::module::ModuleTrait;
use crate::html::{html, Favicon, Markup};

View file

@ -87,7 +87,7 @@
//! use_locale!(LOCALE_SAMPLE["path/to/locale"]);
//! ```
//!
//! Usa el componente [L10n](crate::base::component::L10n) para incluir textos y contenidos
//! Usa el componente [L10n](crate::base::components::L10n) para incluir textos y contenidos
//! opcionalmente traducibles según el contexto de renderizado.
use crate::{args, config, trace, LazyStatic};

View file

@ -32,7 +32,9 @@ pub use crate::core::{action::*, component::*, module::*, theme::*};
pub use crate::{action, action_after_prepare_component, action_before_prepare_component};
pub use crate::base::component::*;
pub use crate::base::actions;
pub use crate::base::components::*;
pub use crate::base::themes;
pub use crate::service;
pub use crate::service::HttpMessage;

View file

@ -3,7 +3,7 @@ pub use error403::ERROR_403;
mod error404;
pub use error404::ERROR_404;
use crate::base::component::L10n;
use crate::base::components::L10n;
use crate::response::{page::Page, ResponseError};
use crate::service::http::{header::ContentType, StatusCode};
use crate::service::{HttpRequest, HttpResponse};

View file

@ -1,10 +1,190 @@
use crate::base::actions;
use crate::base::components::L10n;
use crate::core::component::{ComponentTrait, ContextOp, OneComponent, RenderContext};
use crate::core::theme::ComponentsRegions;
use crate::html::{html, Classes, ClassesOp, Favicon, Markup, DOCTYPE};
use crate::response::fatal_error::FatalError;
use crate::{fn_builder, service};
use unic_langid::CharacterDirection;
pub use actix_web::Result as ResultPage;
mod before_prepare_page;
pub use before_prepare_page::{ActionBeforePreparePage, ACTION_BEFORE_PREPARE_PAGE};
type PageTitle = OneComponent<L10n>;
type PageDescription = OneComponent<L10n>;
mod before_render_page;
pub use before_render_page::{ActionBeforeRenderPage, ACTION_BEFORE_RENDER_PAGE};
#[rustfmt::skip]
pub struct Page {
title : PageTitle,
description : PageDescription,
metadata : Vec<(&'static str, &'static str)>,
properties : Vec<(&'static str, &'static str)>,
favicon : Option<Favicon>,
context : RenderContext,
body_classes: Classes,
regions : ComponentsRegions,
template : String,
}
mod definition;
pub use definition::Page;
impl Default for Page {
#[rustfmt::skip]
fn default() -> Self {
Page {
title : PageTitle::new(),
description : PageDescription::new(),
metadata : Vec::new(),
properties : Vec::new(),
favicon : None,
context : RenderContext::new(),
body_classes: Classes::new().with_value(ClassesOp::SetDefault, "body"),
regions : ComponentsRegions::new(),
template : "default".to_owned(),
}
}
}
impl Page {
pub fn new(request: service::HttpRequest) -> Self {
let mut page = Page::default();
page.context.alter(ContextOp::Request(Some(request)));
page
}
// Page BUILDER.
#[fn_builder]
pub fn alter_title(&mut self, title: L10n) -> &mut Self {
self.title.set(title);
self
}
#[fn_builder]
pub fn alter_description(&mut self, description: L10n) -> &mut Self {
self.description.set(description);
self
}
#[fn_builder]
pub fn alter_metadata(&mut self, name: &'static str, content: &'static str) -> &mut Self {
self.metadata.push((name, content));
self
}
#[fn_builder]
pub fn alter_property(&mut self, property: &'static str, content: &'static str) -> &mut Self {
self.metadata.push((property, content));
self
}
#[fn_builder]
pub fn alter_favicon(&mut self, favicon: Option<Favicon>) -> &mut Self {
self.favicon = favicon;
self
}
#[fn_builder]
pub fn alter_context(&mut self, op: ContextOp) -> &mut Self {
self.context.alter(op);
self
}
#[fn_builder]
pub fn alter_body_classes(&mut self, op: ClassesOp, classes: &str) -> &mut Self {
self.body_classes.alter_value(op, classes);
self
}
#[fn_builder]
pub fn alter_in(&mut self, region: &'static str, component: impl ComponentTrait) -> &mut Self {
self.regions.add_to(region, component);
self
}
#[fn_builder]
pub fn alter_template(&mut self, template: &str) -> &mut Self {
self.template = template.to_owned();
self
}
// Page GETTERS.
pub fn title(&mut self) -> String {
self.title.prepare(&mut self.context).into_string()
}
pub fn description(&mut self) -> String {
self.description.prepare(&mut self.context).into_string()
}
pub fn metadata(&self) -> &Vec<(&str, &str)> {
&self.metadata
}
pub fn properties(&self) -> &Vec<(&str, &str)> {
&self.properties
}
pub fn favicon(&self) -> &Option<Favicon> {
&self.favicon
}
pub fn context(&mut self) -> &mut RenderContext {
&mut self.context
}
pub fn body_classes(&self) -> &Classes {
&self.body_classes
}
pub fn template(&self) -> &str {
self.template.as_str()
}
// Page RENDER.
pub fn render(&mut self) -> ResultPage<Markup, FatalError> {
// Module actions before preparing the page.
actions::page::run_actions_before_prepare_page(self);
// Theme actions before preparing the page.
self.context.theme().before_prepare_page(self);
// Prepare page body.
let body = self.context.theme().prepare_page_body(self);
// Module actions before rendering the page.
actions::page::run_actions_before_render_page(self);
// Theme actions before rendering the page.
self.context.theme().before_render_page(self);
// Prepare page head.
let head = self.context.theme().prepare_page_head(self);
// Render the page.
let lang = self.context.langid().language.as_str();
let dir = match self.context.langid().character_direction() {
CharacterDirection::LTR => "ltr",
CharacterDirection::RTL => "rtl",
};
Ok(html! {
(DOCTYPE)
html lang=(lang) dir=(dir) {
(head)
(body)
}
})
}
pub fn prepare_region(&mut self, region: &str) -> Option<Markup> {
let render = self
.regions
.get_extended_pack(self.context.theme().single_name(), region)
.prepare(self.context());
if render.is_empty() {
None
} else {
Some(render)
}
}
}

View file

@ -1,195 +0,0 @@
use crate::base::component::L10n;
use crate::core::action::{action_ref, run_actions};
use crate::core::component::{ComponentTrait, ContextOp, OneComponent, RenderContext};
use crate::core::theme::ComponentsRegions;
use crate::html::{html, Classes, ClassesOp, Favicon, Markup, DOCTYPE};
use crate::response::fatal_error::FatalError;
use crate::response::page::ResultPage;
use crate::response::page::{ActionBeforePreparePage, ACTION_BEFORE_PREPARE_PAGE};
use crate::response::page::{ActionBeforeRenderPage, ACTION_BEFORE_RENDER_PAGE};
use crate::{fn_builder, service};
use unic_langid::CharacterDirection;
type PageTitle = OneComponent<L10n>;
type PageDescription = OneComponent<L10n>;
#[rustfmt::skip]
pub struct Page {
title : PageTitle,
description : PageDescription,
metadata : Vec<(&'static str, &'static str)>,
properties : Vec<(&'static str, &'static str)>,
favicon : Option<Favicon>,
context : RenderContext,
body_classes: Classes,
regions : ComponentsRegions,
template : String,
}
impl Default for Page {
#[rustfmt::skip]
fn default() -> Self {
Page {
title : PageTitle::new(),
description : PageDescription::new(),
metadata : Vec::new(),
properties : Vec::new(),
favicon : None,
context : RenderContext::new(),
body_classes: Classes::new().with_value(ClassesOp::SetDefault, "body"),
regions : ComponentsRegions::new(),
template : "default".to_owned(),
}
}
}
impl Page {
pub fn new(request: service::HttpRequest) -> Self {
let mut page = Page::default();
page.context.alter(ContextOp::Request(Some(request)));
page
}
// Page BUILDER.
#[fn_builder]
pub fn alter_title(&mut self, title: L10n) -> &mut Self {
self.title.set(title);
self
}
#[fn_builder]
pub fn alter_description(&mut self, description: L10n) -> &mut Self {
self.description.set(description);
self
}
#[fn_builder]
pub fn alter_metadata(&mut self, name: &'static str, content: &'static str) -> &mut Self {
self.metadata.push((name, content));
self
}
#[fn_builder]
pub fn alter_property(&mut self, property: &'static str, content: &'static str) -> &mut Self {
self.metadata.push((property, content));
self
}
#[fn_builder]
pub fn alter_favicon(&mut self, favicon: Option<Favicon>) -> &mut Self {
self.favicon = favicon;
self
}
#[fn_builder]
pub fn alter_context(&mut self, op: ContextOp) -> &mut Self {
self.context.alter(op);
self
}
#[fn_builder]
pub fn alter_body_classes(&mut self, op: ClassesOp, classes: &str) -> &mut Self {
self.body_classes.alter_value(op, classes);
self
}
#[fn_builder]
pub fn alter_in(&mut self, region: &'static str, component: impl ComponentTrait) -> &mut Self {
self.regions.add_to(region, component);
self
}
#[fn_builder]
pub fn alter_template(&mut self, template: &str) -> &mut Self {
self.template = template.to_owned();
self
}
// Page GETTERS.
pub fn title(&mut self) -> String {
self.title.prepare(&mut self.context).into_string()
}
pub fn description(&mut self) -> String {
self.description.prepare(&mut self.context).into_string()
}
pub fn metadata(&self) -> &Vec<(&str, &str)> {
&self.metadata
}
pub fn properties(&self) -> &Vec<(&str, &str)> {
&self.properties
}
pub fn favicon(&self) -> &Option<Favicon> {
&self.favicon
}
pub fn context(&mut self) -> &mut RenderContext {
&mut self.context
}
pub fn body_classes(&self) -> &Classes {
&self.body_classes
}
pub fn template(&self) -> &str {
self.template.as_str()
}
// Page RENDER.
pub fn render(&mut self) -> ResultPage<Markup, FatalError> {
// Module actions before preparing the page.
run_actions(ACTION_BEFORE_PREPARE_PAGE, |action| {
action_ref::<ActionBeforePreparePage>(&**action).run(self)
});
// Theme actions before preparing the page.
self.context.theme().before_prepare_page(self);
// Prepare page body.
let body = self.context.theme().prepare_page_body(self);
// Module actions before rendering the page.
run_actions(ACTION_BEFORE_RENDER_PAGE, |action| {
action_ref::<ActionBeforeRenderPage>(&**action).run(self)
});
// Theme actions before rendering the page.
self.context.theme().before_render_page(self);
// Prepare page head.
let head = self.context.theme().prepare_page_head(self);
// Render the page.
let lang = self.context.langid().language.as_str();
let dir = match self.context.langid().character_direction() {
CharacterDirection::LTR => "ltr",
CharacterDirection::RTL => "rtl",
};
Ok(html! {
(DOCTYPE)
html lang=(lang) dir=(dir) {
(head)
(body)
}
})
}
pub fn prepare_region(&mut self, region: &str) -> Option<Markup> {
let render = self
.regions
.get_extended_pack(self.context.theme().single_name(), region)
.prepare(self.context());
if render.is_empty() {
None
} else {
Some(render)
}
}
}