mod error;
pub use error::ErrorPage;
pub use actix_web::Result as ResultPage;
use crate::base::action;
use crate::core::component::{AssetsOp, ChildOp, Context, ContextError, Contextual};
use crate::core::theme::{DefaultRegion, Region, RegionRef, TemplateRef, ThemeRef};
use crate::html::{html, Markup, DOCTYPE};
use crate::html::{Assets, Favicon, JavaScript, StyleSheet};
use crate::html::{Attr, AttrId};
use crate::html::{Classes, ClassesOp};
use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier};
use crate::service::HttpRequest;
use crate::{builder_fn, AutoDefault};
pub enum ReservedRegion {
PageTop,
PageBottom,
}
impl Region for ReservedRegion {
#[inline]
fn name(&self) -> &'static str {
match self {
Self::PageTop => "page-top",
Self::PageBottom => "page-bottom",
}
}
#[inline]
fn label(&self) -> L10n {
L10n::default()
}
}
#[rustfmt::skip]
#[derive(AutoDefault)]
pub struct Page {
title : Attr<L10n>,
description : Attr<L10n>,
metadata : Vec<(&'static str, &'static str)>,
properties : Vec<(&'static str, &'static str)>,
body_id : AttrId,
body_classes: Classes,
context : Context,
}
impl Page {
#[rustfmt::skip]
pub fn new(request: HttpRequest) -> Self {
Page {
title : Attr::<L10n>::default(),
description : Attr::<L10n>::default(),
metadata : Vec::default(),
properties : Vec::default(),
body_id : AttrId::default(),
body_classes: Classes::default(),
context : Context::new(Some(request)),
}
}
#[builder_fn]
pub fn with_title(mut self, title: L10n) -> Self {
self.title.alter_value(title);
self
}
#[builder_fn]
pub fn with_description(mut self, description: L10n) -> Self {
self.description.alter_value(description);
self
}
#[builder_fn]
pub fn with_metadata(mut self, name: &'static str, content: &'static str) -> Self {
self.metadata.push((name, content));
self
}
#[builder_fn]
pub fn with_property(mut self, property: &'static str, content: &'static str) -> Self {
self.properties.push((property, content));
self
}
#[builder_fn]
pub fn with_body_id(mut self, id: impl AsRef<str>) -> Self {
self.body_id.alter_id(id);
self
}
#[builder_fn]
pub fn with_body_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self {
self.body_classes.alter_classes(op, classes);
self
}
pub fn title(&mut self) -> Option<String> {
self.title.lookup(&self.context)
}
pub fn description(&mut self) -> Option<String> {
self.description.lookup(&self.context)
}
pub fn metadata(&self) -> &Vec<(&str, &str)> {
&self.metadata
}
pub fn properties(&self) -> &Vec<(&str, &str)> {
&self.properties
}
pub fn body_id(&self) -> &AttrId {
&self.body_id
}
pub fn body_classes(&self) -> &Classes {
&self.body_classes
}
pub fn context(&mut self) -> &mut Context {
&mut self.context
}
pub fn render(&mut self) -> ResultPage<Markup, ErrorPage> {
self.context.theme().before_render_page_body(self);
action::page::BeforeRenderBody::dispatch(self);
let body = html! {
(ReservedRegion::PageTop.render(&mut self.context))
(self.context.theme().render_page_body(self))
(ReservedRegion::PageBottom.render(&mut self.context))
};
self.context.theme().after_render_page_body(self);
action::page::AfterRenderBody::dispatch(self);
let head = self.context.theme().render_page_head(self);
let lang = &self.context.langid().language;
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 {
(head)
}
body id=[self.body_id().get()] class=[self.body_classes().get()] {
(body)
}
}
})
}
}
impl LangId for Page {
#[inline]
fn langid(&self) -> &'static LanguageIdentifier {
self.context.langid()
}
}
impl Contextual for Page {
#[builder_fn]
fn with_request(mut self, request: Option<HttpRequest>) -> Self {
self.context.alter_request(request);
self
}
#[builder_fn]
fn with_langid(mut self, language: &impl LangId) -> Self {
self.context.alter_langid(language);
self
}
#[builder_fn]
fn with_theme(mut self, theme: ThemeRef) -> Self {
self.context.alter_theme(theme);
self
}
#[builder_fn]
fn with_template(mut self, template: TemplateRef) -> Self {
self.context.alter_template(template);
self
}
#[builder_fn]
fn with_param<T: 'static>(mut self, key: &'static str, value: T) -> Self {
self.context.alter_param(key, value);
self
}
#[builder_fn]
fn with_assets(mut self, op: AssetsOp) -> Self {
self.context.alter_assets(op);
self
}
#[builder_fn]
fn with_child(mut self, op: impl Into<ChildOp>) -> Self {
self.context
.alter_child_in(&DefaultRegion::Content, op.into());
self
}
#[builder_fn]
fn with_child_in(mut self, region_ref: RegionRef, op: impl Into<ChildOp>) -> Self {
self.context.alter_child_in(region_ref, op.into());
self
}
fn request(&self) -> Option<&HttpRequest> {
self.context.request()
}
fn theme(&self) -> ThemeRef {
self.context.theme()
}
fn template(&self) -> TemplateRef {
self.context.template()
}
fn param<T: 'static>(&self, key: &'static str) -> Result<&T, ContextError> {
self.context.param(key)
}
fn favicon(&self) -> Option<&Favicon> {
self.context.favicon()
}
fn stylesheets(&self) -> &Assets<StyleSheet> {
self.context.stylesheets()
}
fn javascripts(&self) -> &Assets<JavaScript> {
self.context.javascripts()
}
fn remove_param(&mut self, key: &'static str) -> bool {
self.context.remove_param(key)
}
}