mod error; pub use error::ErrorPage; pub use actix_web::Result as ResultPage; use crate::base::action; use crate::core::component::{AnyComponents, ArcAnyComponent, ComponentTrait}; use crate::core::component::{Context, ContextOp}; use crate::core::theme::ComponentsInRegions; use crate::fn_builder; use crate::html::{html, Markup, DOCTYPE}; use crate::html::{ClassesOp, Favicon, OptionClasses, OptionId, OptionTranslated}; use crate::locale::L10n; use crate::{fn_with, service}; use unic_langid::CharacterDirection; #[rustfmt::skip] pub struct Page { title : OptionTranslated, description : OptionTranslated, metadata : Vec<(&'static str, &'static str)>, properties : Vec<(&'static str, &'static str)>, favicon : Option, context : Context, body_id : OptionId, body_classes: OptionClasses, skip_to : OptionId, regions : ComponentsInRegions, template : String, } impl Page { #[rustfmt::skip] pub fn new(request: service::HttpRequest) -> Self { Page { title : OptionTranslated::default(), description : OptionTranslated::default(), metadata : Vec::default(), properties : Vec::default(), favicon : None, context : Context::new(request), body_id : OptionId::default(), body_classes: OptionClasses::default(), skip_to : OptionId::default(), regions : ComponentsInRegions::default(), template : "default".to_owned(), } } // Page BUILDER. #[fn_builder] pub fn alter_title(&mut self, title: L10n) -> &mut Self { self.title.alter_value(title); self } #[fn_builder] pub fn alter_description(&mut self, description: L10n) -> &mut Self { self.description.alter_value(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) -> &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_id(&mut self, id: impl Into) -> &mut Self { self.body_id.alter_value(id); self } #[fn_builder] pub fn alter_body_classes(&mut self, op: ClassesOp, classes: impl Into) -> &mut Self { self.body_classes.alter_value(op, classes); self } #[fn_builder] pub fn alter_skip_to(&mut self, id: impl Into) -> &mut Self { self.skip_to.alter_value(id); self } #[fn_builder] pub fn alter_component(&mut self, component: impl ComponentTrait) -> &mut Self { self.regions .add_component_in("content", ArcAnyComponent::new(component)); self } #[fn_builder] pub fn alter_component_in( &mut self, region: &'static str, component: impl ComponentTrait, ) -> &mut Self { self.regions .add_component_in(region, ArcAnyComponent::new(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) -> Option { self.title.using(self.context.langid()) } pub fn description(&mut self) -> Option { self.description.using(self.context.langid()) } pub fn metadata(&self) -> &Vec<(&str, &str)> { &self.metadata } pub fn properties(&self) -> &Vec<(&str, &str)> { &self.properties } pub fn favicon(&self) -> &Option { &self.favicon } pub fn context(&mut self) -> &mut Context { &mut self.context } pub fn body_id(&self) -> &OptionId { &self.body_id } pub fn body_classes(&self) -> &OptionClasses { &self.body_classes } pub fn skip_to(&self) -> &OptionId { &self.skip_to } pub fn components_in(&self, region: &str) -> AnyComponents { self.regions.get_components(self.context.theme(), region) } pub fn template(&self) -> &str { self.template.as_str() } // Page RENDER. pub fn render(&mut self) -> ResultPage { // Theme actions before preparing the page body. self.context.theme().before_prepare_body(self); // Packages actions before preparing the page body. action::page::BeforePrepareBody::dispatch(self); // Prepare page body. let body = self.context.theme().prepare_body(self); // Theme actions after preparing the page body. self.context.theme().after_prepare_body(self); // Packages actions after preparing the page body. action::page::AfterPrepareBody::dispatch(self); // Prepare page head. let head = self.context.theme().prepare_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", CharacterDirection::TTB => "auto", }; Ok(html! { (DOCTYPE) html lang=(lang) dir=(dir) { (head) (body) } }) } }