diff --git a/pagetop/src/core/component/context.rs b/pagetop/src/core/component/context.rs index 1b12f955..16a077a7 100644 --- a/pagetop/src/core/component/context.rs +++ b/pagetop/src/core/component/context.rs @@ -1,6 +1,6 @@ use crate::core::theme::all::{theme_by_single_name, THEME}; use crate::core::theme::ThemeStaticRef; -use crate::html::{html, Assets, JavaScript, Markup, StyleSheet}; +use crate::html::{html, Assets, HeadScript, HeadStyles, JavaScript, Markup, StyleSheet}; use crate::locale::{LanguageIdentifier, LANGID}; use crate::service::HttpRequest; use crate::{concat_string, util}; @@ -11,21 +11,31 @@ use std::str::FromStr; pub enum ContextOp { LangId(&'static LanguageIdentifier), Theme(&'static str), + // Stylesheets. AddStyleSheet(StyleSheet), RemoveStyleSheet(&'static str), + // Styles in head. + AddHeadStyles(HeadStyles), + RemoveHeadStyles(&'static str), + // JavaScripts. AddJavaScript(JavaScript), RemoveJavaScript(&'static str), + // Scripts in head. + AddHeadScript(HeadScript), + RemoveHeadScript(&'static str), } #[rustfmt::skip] pub struct Context { - request : HttpRequest, - langid : &'static LanguageIdentifier, - theme : ThemeStaticRef, - stylesheets: Assets, - javascripts: Assets, - params : HashMap<&'static str, String>, - id_counter : usize, + request : HttpRequest, + langid : &'static LanguageIdentifier, + theme : ThemeStaticRef, + stylesheet: Assets, // Stylesheets. + headstyles: Assets, // Styles in head. + javascript: Assets, // JavaScripts. + headscript: Assets, // Scripts in head. + params : HashMap<&'static str, String>, + id_counter: usize, } impl Context { @@ -33,15 +43,18 @@ impl Context { pub(crate) fn new(request: HttpRequest) -> Self { Context { request, - langid : &LANGID, - theme : *THEME, - stylesheets: Assets::::new(), - javascripts: Assets::::new(), - params : HashMap::<&str, String>::new(), - id_counter : 0, + langid : &LANGID, + theme : *THEME, + stylesheet: Assets::::new(), // Stylesheets. + headstyles: Assets::::new(), // Styles in head. + javascript: Assets::::new(), // JavaScripts. + headscript: Assets::::new(), // Scripts in head. + params : HashMap::<&str, String>::new(), + id_counter: 0, } } + #[rustfmt::skip] pub fn alter(&mut self, op: ContextOp) -> &mut Self { match op { ContextOp::LangId(langid) => { @@ -50,18 +63,18 @@ impl Context { ContextOp::Theme(theme_name) => { self.theme = theme_by_single_name(theme_name).unwrap_or(*THEME); } - ContextOp::AddStyleSheet(css) => { - self.stylesheets.add(css); - } - ContextOp::RemoveStyleSheet(source) => { - self.stylesheets.remove(source); - } - ContextOp::AddJavaScript(js) => { - self.javascripts.add(js); - } - ContextOp::RemoveJavaScript(source) => { - self.javascripts.remove(source); - } + // Stylesheets. + ContextOp::AddStyleSheet(css) => { self.stylesheet.add(css); } + ContextOp::RemoveStyleSheet(path) => { self.stylesheet.remove(path); } + // Styles in head. + ContextOp::AddHeadStyles(styles) => { self.headstyles.add(styles); } + ContextOp::RemoveHeadStyles(path) => { self.headstyles.remove(path); } + // JavaScripts. + ContextOp::AddJavaScript(js) => { self.javascript.add(js); } + ContextOp::RemoveJavaScript(path) => { self.javascript.remove(path); } + // Scripts in head. + ContextOp::AddHeadScript(script) => { self.headscript.add(script); } + ContextOp::RemoveHeadScript(path) => { self.headscript.remove(path); } } self } @@ -71,6 +84,11 @@ impl Context { self } + pub fn remove_param(&mut self, key: &'static str) -> &mut Self { + self.params.remove(key); + self + } + /// Context GETTERS. pub fn request(&self) -> &HttpRequest { @@ -98,8 +116,10 @@ impl Context { pub fn prepare(&mut self) -> Markup { html! { - (self.stylesheets.prepare()) - (self.javascripts.prepare()) + (self.stylesheet.prepare()) // Stylesheets. + (self.headstyles.prepare()) // Styles in head. + (self.javascript.prepare()) // JavaScripts. + (self.headscript.prepare()) // Scripts in head. } } diff --git a/pagetop/src/html.rs b/pagetop/src/html.rs index b9dbd78e..c0ebacc5 100644 --- a/pagetop/src/html.rs +++ b/pagetop/src/html.rs @@ -4,6 +4,8 @@ mod maud; pub use maud::{html, html_private, Markup, PreEscaped, DOCTYPE}; mod assets; +pub use assets::headscript::HeadScript; +pub use assets::headstyles::HeadStyles; pub use assets::javascript::{JavaScript, ModeJS}; pub use assets::stylesheet::{StyleSheet, TargetMedia}; pub use assets::Assets; diff --git a/pagetop/src/html/assets.rs b/pagetop/src/html/assets.rs index 6ca33c81..2006dae7 100644 --- a/pagetop/src/html/assets.rs +++ b/pagetop/src/html/assets.rs @@ -1,10 +1,12 @@ +pub mod headscript; +pub mod headstyles; pub mod javascript; pub mod stylesheet; use crate::html::{html, Markup}; pub trait AssetsTrait { - fn source(&self) -> &str; + fn path(&self) -> &str; fn weight(&self) -> isize; @@ -20,7 +22,7 @@ impl Assets { } pub fn add(&mut self, asset: T) -> &mut Self { - match self.0.iter().position(|x| x.source() == asset.source()) { + match self.0.iter().position(|x| x.path() == asset.path()) { Some(index) => { if self.0[index].weight() > asset.weight() { self.0.remove(index); @@ -32,8 +34,8 @@ impl Assets { self } - pub fn remove(&mut self, source: &'static str) -> &mut Self { - if let Some(index) = self.0.iter().position(|x| x.source() == source) { + pub fn remove(&mut self, path: &'static str) -> &mut Self { + if let Some(index) = self.0.iter().position(|x| x.path() == path) { self.0.remove(index); }; self diff --git a/pagetop/src/html/assets/headscript.rs b/pagetop/src/html/assets/headscript.rs new file mode 100644 index 00000000..ed7eccd5 --- /dev/null +++ b/pagetop/src/html/assets/headscript.rs @@ -0,0 +1,46 @@ +use super::AssetsTrait; +use crate::html::{html, Markup}; + +#[rustfmt::skip] +#[derive(Default)] +pub struct HeadScript { + path : String, + code : String, + weight: isize, +} + +impl AssetsTrait for HeadScript { + fn path(&self) -> &str { + self.path.as_str() + } + + fn weight(&self) -> isize { + self.weight + } + + fn prepare(&self) -> Markup { + html! { script { (self.code) }; } + } +} + +impl HeadScript { + pub fn named(path: S) -> Self + where + S: Into, + { + HeadScript { + path: path.into(), + ..Default::default() + } + } + + pub fn with_code(mut self, code: &str) -> Self { + self.code = code.trim().to_owned(); + self + } + + pub fn with_weight(mut self, weight: isize) -> Self { + self.weight = weight; + self + } +} diff --git a/pagetop/src/html/assets/headstyles.rs b/pagetop/src/html/assets/headstyles.rs new file mode 100644 index 00000000..888ef21e --- /dev/null +++ b/pagetop/src/html/assets/headstyles.rs @@ -0,0 +1,46 @@ +use super::AssetsTrait; +use crate::html::{html, Markup}; + +#[rustfmt::skip] +#[derive(Default)] +pub struct HeadStyles { + path : String, + styles: String, + weight: isize, +} + +impl AssetsTrait for HeadStyles { + fn path(&self) -> &str { + self.path.as_str() + } + + fn weight(&self) -> isize { + self.weight + } + + fn prepare(&self) -> Markup { + html! { styles { (self.styles) }; } + } +} + +impl HeadStyles { + pub fn named(path: S) -> Self + where + S: Into, + { + HeadStyles { + path: path.into(), + ..Default::default() + } + } + + pub fn with_styles(mut self, styles: &str) -> Self { + self.styles = styles.trim().to_owned(); + self + } + + pub fn with_weight(mut self, weight: isize) -> Self { + self.weight = weight; + self + } +} diff --git a/pagetop/src/html/assets/javascript.rs b/pagetop/src/html/assets/javascript.rs index 848c81bc..44af052a 100644 --- a/pagetop/src/html/assets/javascript.rs +++ b/pagetop/src/html/assets/javascript.rs @@ -12,14 +12,16 @@ pub enum ModeJS { #[rustfmt::skip] #[derive(Default)] pub struct JavaScript { - source : String, + path : String, + prefix : &'static str, + version: &'static str, weight : isize, mode : ModeJS, } impl AssetsTrait for JavaScript { - fn source(&self) -> &str { - self.source.as_str() + fn path(&self) -> &str { + self.path.as_str() } fn weight(&self) -> isize { @@ -29,7 +31,7 @@ impl AssetsTrait for JavaScript { fn prepare(&self) -> Markup { html! { script type="text/javascript" - src=(self.source) + src=(crate::concat_string!(self.path, self.prefix, self.version)) async[self.mode == ModeJS::Async] defer[self.mode == ModeJS::Defer] {}; @@ -38,16 +40,25 @@ impl AssetsTrait for JavaScript { } impl JavaScript { - pub fn located(source: S) -> Self + pub fn located(path: S) -> Self where S: Into, { JavaScript { - source: source.into(), + path: path.into(), ..Default::default() } } + pub fn with_version(mut self, version: &'static str) -> Self { + (self.prefix, self.version) = if version.is_empty() { + ("", "") + } else { + ("?v=", version) + }; + self + } + pub fn with_weight(mut self, weight: isize) -> Self { self.weight = weight; self diff --git a/pagetop/src/html/assets/stylesheet.rs b/pagetop/src/html/assets/stylesheet.rs index 0afecfb7..c8347591 100644 --- a/pagetop/src/html/assets/stylesheet.rs +++ b/pagetop/src/html/assets/stylesheet.rs @@ -11,14 +11,16 @@ pub enum TargetMedia { #[rustfmt::skip] #[derive(Default)] pub struct StyleSheet { - source : String, + path : String, + prefix : &'static str, + version: &'static str, media : Option<&'static str>, weight : isize, } impl AssetsTrait for StyleSheet { - fn source(&self) -> &str { - self.source.as_str() + fn path(&self) -> &str { + self.path.as_str() } fn weight(&self) -> isize { @@ -26,21 +28,35 @@ impl AssetsTrait for StyleSheet { } fn prepare(&self) -> Markup { - html! { link rel="stylesheet" href=(self.source) media=[self.media]; } + html! { + link + rel="stylesheet" + href=(crate::concat_string!(self.path, self.prefix, self.version)) + media=[self.media]; + } } } impl StyleSheet { - pub fn located(source: S) -> Self + pub fn located(path: S) -> Self where S: Into, { StyleSheet { - source: source.into(), + path: path.into(), ..Default::default() } } + pub fn with_version(mut self, version: &'static str) -> Self { + (self.prefix, self.version) = if version.is_empty() { + ("", "") + } else { + ("?v=", version) + }; + self + } + pub fn with_weight(mut self, weight: isize) -> Self { self.weight = weight; self