diff --git a/pagetop/src/base/component/anchor.rs b/pagetop/src/base/component/anchor.rs index d0534694..1d0ce8a1 100644 --- a/pagetop/src/base/component/anchor.rs +++ b/pagetop/src/base/component/anchor.rs @@ -55,7 +55,7 @@ impl ComponentTrait for Anchor { self.weight } - fn default_render(&self, _: &mut Assets) -> Markup { + fn default_render(&self, _: &mut Context) -> Markup { let target = match &self.target() { AnchorTarget::Blank => Some("_blank"), AnchorTarget::Context(name) => Some(name.as_str()), diff --git a/pagetop/src/base/component/block.rs b/pagetop/src/base/component/block.rs index 4f120434..a37bc2ed 100644 --- a/pagetop/src/base/component/block.rs +++ b/pagetop/src/base/component/block.rs @@ -37,8 +37,8 @@ impl ComponentTrait for Block { self.weight } - fn default_render(&self, assets: &mut Assets) -> Markup { - let id = assets.required_id::(self.id()); + fn default_render(&self, context: &mut Context) -> Markup { + let id = context.required_id::(self.id()); html! { div id=(id) class=[self.classes()] { @match self.title() { @@ -46,7 +46,7 @@ impl ComponentTrait for Block { None => {} } div class="block-body" { - (self.components().render(assets)) + (self.components().render(context)) } } } diff --git a/pagetop/src/base/component/chunck.rs b/pagetop/src/base/component/chunck.rs index c7d8a978..fdbfe9ee 100644 --- a/pagetop/src/base/component/chunck.rs +++ b/pagetop/src/base/component/chunck.rs @@ -31,7 +31,7 @@ impl ComponentTrait for Chunck { self.weight } - fn default_render(&self, _: &mut Assets) -> Markup { + fn default_render(&self, _: &mut Context) -> Markup { html! { (*self.html()) } } diff --git a/pagetop/src/base/component/container.rs b/pagetop/src/base/component/container.rs index e275f255..7be54148 100644 --- a/pagetop/src/base/component/container.rs +++ b/pagetop/src/base/component/container.rs @@ -41,39 +41,39 @@ impl ComponentTrait for Container { self.weight } - fn default_render(&self, assets: &mut Assets) -> Markup { + fn default_render(&self, context: &mut Context) -> Markup { match self.container_type() { ContainerType::Header => html! { header id=[self.id()] class=[self.classes()] { div class=[self.inner_classes()] { - (self.components().render(assets)) + (self.components().render(context)) } } }, ContainerType::Footer => html! { footer id=[self.id()] class=[self.classes()] { div class=[self.inner_classes()] { - (self.components().render(assets)) + (self.components().render(context)) } } }, ContainerType::Main => html! { main id=[self.id()] class=[self.classes()] { div class=[self.inner_classes()] { - (self.components().render(assets)) + (self.components().render(context)) } } }, ContainerType::Section => html! { section id=[self.id()] class=[self.classes()] { div class=[self.inner_classes()] { - (self.components().render(assets)) + (self.components().render(context)) } } }, _ => html! { div id=[self.id()] class=[self.classes()] { - (self.components().render(assets)) + (self.components().render(context)) } } } diff --git a/pagetop/src/base/component/form/button.rs b/pagetop/src/base/component/form/button.rs index fc7fe620..ad042b60 100644 --- a/pagetop/src/base/component/form/button.rs +++ b/pagetop/src/base/component/form/button.rs @@ -44,7 +44,7 @@ impl ComponentTrait for Button { self.weight } - fn default_render(&self, _: &mut Assets) -> Markup { + fn default_render(&self, _: &mut Context) -> Markup { let button_type = match self.button_type() { ButtonType::Button => "button", ButtonType::Reset => "reset", diff --git a/pagetop/src/base/component/form/date.rs b/pagetop/src/base/component/form/date.rs index eeb1d7aa..763a474a 100644 --- a/pagetop/src/base/component/form/date.rs +++ b/pagetop/src/base/component/form/date.rs @@ -52,7 +52,7 @@ impl ComponentTrait for Date { self.weight } - fn default_render(&self, _: &mut Assets) -> Markup { + fn default_render(&self, _: &mut Context) -> Markup { let id = match self.name() { Some(name) => Some(concat_string!("edit-", name)), None => None, diff --git a/pagetop/src/base/component/form/form.rs b/pagetop/src/base/component/form/form.rs index dcf209b0..688eeeed 100644 --- a/pagetop/src/base/component/form/form.rs +++ b/pagetop/src/base/component/form/form.rs @@ -43,7 +43,7 @@ impl ComponentTrait for Form { self.weight } - fn default_render(&self, assets: &mut Assets) -> Markup { + fn default_render(&self, context: &mut Context) -> Markup { let method = match self.method() { FormMethod::Get => None, FormMethod::Post => Some("post".to_owned()) @@ -56,7 +56,7 @@ impl ComponentTrait for Form { method=[method] accept-charset=[self.charset()] { - div { (self.elements().render(assets)) } + div { (self.elements().render(context)) } } } } diff --git a/pagetop/src/base/component/form/hidden.rs b/pagetop/src/base/component/form/hidden.rs index c8d86131..91a2986f 100644 --- a/pagetop/src/base/component/form/hidden.rs +++ b/pagetop/src/base/component/form/hidden.rs @@ -25,7 +25,7 @@ impl ComponentTrait for Hidden { self.weight } - fn default_render(&self, _: &mut Assets) -> Markup { + fn default_render(&self, _: &mut Context) -> Markup { let id = match self.name() { Some(name) => Some(concat_string!("value-", name)), _ => None diff --git a/pagetop/src/base/component/form/input.rs b/pagetop/src/base/component/form/input.rs index d1614aa3..806be50a 100644 --- a/pagetop/src/base/component/form/input.rs +++ b/pagetop/src/base/component/form/input.rs @@ -62,14 +62,14 @@ impl ComponentTrait for Input { self.weight } - fn before_render(&mut self, _: &mut Assets) { + fn before_render(&mut self, _: &mut Context) { if let Some(name) = self.name() { let class = concat_string!("form-item-", name); self.alter_classes(class.as_str(), ClassesOp::AddFirst); } } - fn default_render(&self, _: &mut Assets) -> Markup { + fn default_render(&self, _: &mut Context) -> Markup { let type_input = match self.input_type() { InputType::Email => "email", InputType::Password => "password", diff --git a/pagetop/src/base/component/grid/column.rs b/pagetop/src/base/component/grid/column.rs index a69edce7..b06faea2 100644 --- a/pagetop/src/base/component/grid/column.rs +++ b/pagetop/src/base/component/grid/column.rs @@ -35,10 +35,10 @@ impl ComponentTrait for Column { self.weight } - fn default_render(&self, assets: &mut Assets) -> Markup { + fn default_render(&self, context: &mut Context) -> Markup { html! { div id=[self.id()] class=[self.classes()] { - (self.components().render(assets)) + (self.components().render(context)) } } } diff --git a/pagetop/src/base/component/grid/row.rs b/pagetop/src/base/component/grid/row.rs index 05fae1cf..0ffe3f08 100644 --- a/pagetop/src/base/component/grid/row.rs +++ b/pagetop/src/base/component/grid/row.rs @@ -35,10 +35,10 @@ impl ComponentTrait for Row { self.weight } - fn default_render(&self, assets: &mut Assets) -> Markup { + fn default_render(&self, context: &mut Context) -> Markup { html! { div id=[self.id()] class=[self.classes()] { - (self.columns().render(assets)) + (self.columns().render(context)) } } } diff --git a/pagetop/src/base/component/heading.rs b/pagetop/src/base/component/heading.rs index fa17ca7e..eada3ea5 100644 --- a/pagetop/src/base/component/heading.rs +++ b/pagetop/src/base/component/heading.rs @@ -50,7 +50,7 @@ impl ComponentTrait for Heading { self.weight } - fn default_render(&self, _: &mut Assets) -> Markup { + fn default_render(&self, _: &mut Context) -> Markup { html! { @match &self.heading() { HeadingType::H1 => h1 id=[self.id()] class=[self.classes()] { (*self.html()) }, HeadingType::H2 => h2 id=[self.id()] class=[self.classes()] { (*self.html()) }, diff --git a/pagetop/src/base/component/image.rs b/pagetop/src/base/component/image.rs index 300cafc2..5a3f16c6 100644 --- a/pagetop/src/base/component/image.rs +++ b/pagetop/src/base/component/image.rs @@ -35,7 +35,7 @@ impl ComponentTrait for Image { self.weight } - fn default_render(&self, _: &mut Assets) -> Markup { + fn default_render(&self, _: &mut Context) -> Markup { html! { img src=[self.source()] diff --git a/pagetop/src/base/component/menu.rs b/pagetop/src/base/component/menu.rs index 6fa41268..c4a97a05 100644 --- a/pagetop/src/base/component/menu.rs +++ b/pagetop/src/base/component/menu.rs @@ -42,7 +42,7 @@ impl ComponentTrait for MenuItem { self.weight } - fn default_render(&self, assets: &mut Assets) -> Markup { + fn default_render(&self, context: &mut Context) -> Markup { match self.item_type() { MenuItemType::Label(label) => html! { li class="label" { a href="#" { (label) } } @@ -62,7 +62,7 @@ impl ComponentTrait for MenuItem { li class="submenu" { a href="#" { (label) } ul { - (menu.items().render(assets)) + (menu.items().render(context)) } } }, @@ -206,8 +206,8 @@ impl ComponentTrait for Menu { self.weight } - fn default_render(&self, assets: &mut Assets) -> Markup { - assets + fn default_render(&self, context: &mut Context) -> Markup { + context .add_stylesheet(StyleSheet::source( "/theme/menu/css/menu.css?ver=1.1.1" )) @@ -219,10 +219,10 @@ impl ComponentTrait for Menu { )) .add_jquery(); - let id = assets.required_id::(self.id()); + let id = context.required_id::(self.id()); html! { ul id=(id) class=[self.classes()] { - (self.items().render(assets)) + (self.items().render(context)) } script type="text/javascript" defer { "jQuery(function(){jQuery('#" (id) "').smartmenus({" diff --git a/pagetop/src/base/component/paragraph.rs b/pagetop/src/base/component/paragraph.rs index 025d9565..d8e1ac4b 100644 --- a/pagetop/src/base/component/paragraph.rs +++ b/pagetop/src/base/component/paragraph.rs @@ -46,7 +46,7 @@ impl ComponentTrait for Paragraph { self.weight } - fn default_render(&self, _: &mut Assets) -> Markup { + fn default_render(&self, _: &mut Context) -> Markup { html! { p id=[self.id()] class=[self.classes()] { (*self.html()) } } diff --git a/pagetop/src/base/theme/aliner.rs b/pagetop/src/base/theme/aliner.rs index d27c4632..ae6c7475 100644 --- a/pagetop/src/base/theme/aliner.rs +++ b/pagetop/src/base/theme/aliner.rs @@ -16,7 +16,7 @@ impl ThemeTrait for Aliner { } fn before_render_page(&self, page: &mut Page) { - page.assets() + page.context() .with_favicon( Favicon::new() .with_icon("/theme/favicon.png") diff --git a/pagetop/src/base/theme/bootsier.rs b/pagetop/src/base/theme/bootsier.rs index 5471b5cf..494bda17 100644 --- a/pagetop/src/base/theme/bootsier.rs +++ b/pagetop/src/base/theme/bootsier.rs @@ -18,7 +18,7 @@ impl ThemeTrait for Bootsier { } fn before_render_page(&self, page: &mut Page) { - page.assets() + page.context() .with_favicon( Favicon::new() .with_icon("/theme/favicon.png") diff --git a/pagetop/src/base/theme/bulmix.rs b/pagetop/src/base/theme/bulmix.rs index b4a360fb..e6041798 100644 --- a/pagetop/src/base/theme/bulmix.rs +++ b/pagetop/src/base/theme/bulmix.rs @@ -16,7 +16,7 @@ impl ThemeTrait for Bulmix { } fn before_render_page(&self, page: &mut Page) { - page.assets() + page.context() .with_favicon( Favicon::new() .with_icon("/theme/favicon.png") @@ -33,7 +33,7 @@ impl ThemeTrait for Bulmix { fn before_render_component( &self, component: &mut dyn ComponentTrait, - _assets: &mut Assets + _context: &mut Context ) { match component.handler() { HEADING_COMPONENT => { diff --git a/pagetop/src/core/component.rs b/pagetop/src/core/component.rs index c0c78a57..f11f6b1b 100644 --- a/pagetop/src/core/component.rs +++ b/pagetop/src/core/component.rs @@ -4,9 +4,9 @@ pub use hook::{ BeforeRenderComponentHook, }; -mod assets; -pub use assets::{ - Assets, +mod context; +pub use context::{ + Context, Favicon, JavaScript, JSMode, StyleSheet, diff --git a/pagetop/src/core/component/assets.rs b/pagetop/src/core/component/assets.rs deleted file mode 100644 index 563e33c9..00000000 --- a/pagetop/src/core/component/assets.rs +++ /dev/null @@ -1,302 +0,0 @@ -use crate::{Lazy, base, concat_string, util}; -use crate::config::SETTINGS; -use crate::html::{Markup, PreEscaped, html}; -use crate::core::theme::*; - -static DEFAULT_THEME: Lazy<&dyn ThemeTrait> = Lazy::new(|| { - match all::theme_by_single_name(&SETTINGS.app.theme) { - Some(theme) => theme, - None => &base::theme::bootsier::Bootsier, - } -}); - -// Favicon. - -pub struct Favicon(Vec); - -impl Favicon { - pub fn new() -> Self { - Favicon(Vec::new()) - } - - pub fn with_icon(self, image: &str) -> Self { - self.add_item("icon", image, "", "") - } - - pub fn with_icon_for_sizes(self, image: &str, sizes: &str) -> Self { - self.add_item("icon", image, sizes, "") - } - - pub fn with_apple_touch_icon(self, image: &str, sizes: &str) -> Self { - self.add_item("apple-touch-icon", image, sizes, "") - } - - pub fn with_mask_icon(self, image: &str, color: &str) -> Self { - self.add_item("mask-icon", image, "", color) - } - - pub fn with_manifest(self, file: &str) -> Self { - self.add_item("manifest", file, "", "") - } - - pub fn with_theme_color(mut self, color: &str) -> Self { - self.0.push(format!( - "", color - )); - self - } - - pub fn with_ms_tile_color(mut self, color: &str) -> Self { - self.0.push(format!( - "", color - )); - self - } - - pub fn with_ms_tile_image(mut self, image: &str) -> Self { - self.0.push(format!( - "", image - )); - self - } - - fn add_item( - mut self, - rel : &str, - source: &str, - sizes : &str, - color : &str - ) -> Self { - let mut link: String = format!(" format!("{} type=\"image/gif\"", link), - ".ico" => format!("{} type=\"image/x-icon\"", link), - ".jpg" => format!("{} type=\"image/jpg\"", link), - ".png" => format!("{} type=\"image/png\"", link), - ".svg" => format!("{} type=\"image/svg+xml\"", link), - _ => link - }; - } - if !sizes.is_empty() { - link = format!("{} sizes=\"{}\"", link, sizes); - } - if !color.is_empty() { - link = format!("{} color=\"{}\"", link, color); - } - self.0.push(format!("{} href=\"{}\">", link, source)); - self - } - - fn render(&self) -> Markup { - html! { - @for item in &self.0 { - (PreEscaped(item)) - } - } - } -} - -// JavaScript. - -#[derive(PartialEq)] -pub enum JSMode { Async, Defer, Normal } - -pub struct JavaScript { - source: &'static str, - weight: isize, - mode : JSMode, -} -impl JavaScript { - pub fn source(s: &'static str) -> Self { - JavaScript { - source: s, - weight: 0, - mode : JSMode::Defer, - } - } - - pub fn with_weight(mut self, weight: isize) -> Self { - self.weight = weight; - self - } - - pub fn with_mode(mut self, mode: JSMode) -> Self { - self.mode = mode; - self - } - - pub fn weight(self) -> isize { - self.weight - } - - fn render(&self) -> Markup { - html! { - script type="text/javascript" - src=(self.source) - async[self.mode == JSMode::Async] - defer[self.mode == JSMode::Defer] - {}; - } - } -} - -// StyleSheet. - -pub struct StyleSheet { - source: &'static str, - weight: isize, -} -impl StyleSheet { - pub fn source(s: &'static str) -> Self { - StyleSheet { - source: s, - weight: 0, - } - } - - pub fn with_weight(mut self, weight: isize) -> Self { - self.weight = weight; - self - } - - pub fn weight(self) -> isize { - self.weight - } - - fn render(&self) -> Markup { - html! { - link rel="stylesheet" href=(self.source); - } - } -} - -// Page assets. - -pub struct Assets { - theme : &'static dyn ThemeTrait, - favicon : Option, - metadata : Vec<(String, String)>, - stylesheets: Vec, - javascripts: Vec, - with_jquery: bool, - id_counter : usize, -} - -impl Assets { - pub fn new() -> Self { - Assets { - theme : *DEFAULT_THEME, - favicon : None, - metadata : Vec::new(), - stylesheets: Vec::new(), - javascripts: Vec::new(), - with_jquery: false, - id_counter : 0, - } - } - - pub fn using_theme(&mut self, theme_name: &str) -> &mut Self { - self.theme = all::theme_by_single_name(theme_name).unwrap_or(*DEFAULT_THEME); - self - } - - pub fn with_favicon(&mut self, favicon: Favicon) -> &mut Self { - self.favicon = Some(favicon); - self - } - - pub fn add_metadata(&mut self, name: String, content: String) -> &mut Self { - self.metadata.push((name, content)); - self - } - - pub fn add_stylesheet(&mut self, css: StyleSheet) -> &mut Self { - match self.stylesheets.iter().position(|x| x.source == css.source) { - Some(index) => if self.stylesheets[index].weight > css.weight { - self.stylesheets.remove(index); - self.stylesheets.push(css); - }, - _ => self.stylesheets.push(css) - } - self - } - - pub fn add_javascript(&mut self, js: JavaScript) -> &mut Self { - match self.javascripts.iter().position(|x| x.source == js.source) { - Some(index) => if self.javascripts[index].weight > js.weight { - self.javascripts.remove(index); - self.javascripts.push(js); - }, - _ => self.javascripts.push(js) - } - self - } - - pub fn add_jquery(&mut self) -> &mut Self { - if !self.with_jquery { - self.add_javascript( - JavaScript::source( - "/theme/js/jquery.min.js?ver=3.6.0" - ) - .with_weight(isize::MIN) - .with_mode(JSMode::Normal) - ); - self.with_jquery = true; - } - self - } - - /// Assets GETTERS. - - pub(crate) fn theme(&mut self) -> &'static dyn ThemeTrait { - self.theme - } - - /// Assets RENDER. - - pub fn render(&mut self) -> Markup { - let ordered_css = &mut self.stylesheets; - ordered_css.sort_by_key(|o| o.weight); - - let ordered_js = &mut self.javascripts; - ordered_js.sort_by_key(|o| o.weight); - - html! { - @match &self.favicon { - Some(favicon) => (favicon.render()), - None => "", - } - @for (name, content) in &self.metadata { - meta name=(name) content=(content) {} - } - @for css in ordered_css { - (css.render()) - } - @for js in ordered_js { - (js.render()) - } - } - } - - // Assets EXTRAS. - - pub fn required_id(&mut self, id: &Option) -> String { - match id { - Some(id) => id.to_string(), - None => { - let prefix = util::single_type_name::() - .trim() - .replace(" ", "_") - .to_lowercase(); - let prefix = if prefix.is_empty() { - "prefix".to_owned() - } else { - prefix - }; - self.id_counter += 1; - concat_string!(prefix, "-", self.id_counter.to_string()) - } - } - } -} diff --git a/pagetop/src/core/component/context.rs b/pagetop/src/core/component/context.rs new file mode 100644 index 00000000..3aeab266 --- /dev/null +++ b/pagetop/src/core/component/context.rs @@ -0,0 +1,148 @@ +use crate::{Lazy, base, concat_string, util}; +use crate::config::SETTINGS; +use crate::html::{Markup, html}; +use crate::core::theme::*; + +mod favicon; +pub use favicon::Favicon; + +mod javascript; +pub use javascript::{JavaScript, JSMode}; + +mod stylesheet; +pub use stylesheet::StyleSheet; + +static DEFAULT_THEME: Lazy<&dyn ThemeTrait> = Lazy::new(|| { + match all::theme_by_single_name(&SETTINGS.app.theme) { + Some(theme) => theme, + None => &base::theme::bootsier::Bootsier, + } +}); + +pub struct Context { + theme : &'static dyn ThemeTrait, + favicon : Option, + metadata : Vec<(String, String)>, + stylesheets: Vec, + javascripts: Vec, + with_jquery: bool, + id_counter : usize, +} + +impl Context { + pub fn new() -> Self { + Context { + theme : *DEFAULT_THEME, + favicon : None, + metadata : Vec::new(), + stylesheets: Vec::new(), + javascripts: Vec::new(), + with_jquery: false, + id_counter : 0, + } + } + + pub fn using_theme(&mut self, theme_name: &str) -> &mut Self { + self.theme = all::theme_by_single_name(theme_name).unwrap_or(*DEFAULT_THEME); + self + } + + pub fn with_favicon(&mut self, favicon: Favicon) -> &mut Self { + self.favicon = Some(favicon); + self + } + + pub fn add_metadata(&mut self, name: String, content: String) -> &mut Self { + self.metadata.push((name, content)); + self + } + + pub fn add_stylesheet(&mut self, css: StyleSheet) -> &mut Self { + match self.stylesheets.iter().position(|x| x.source == css.source) { + Some(index) => if self.stylesheets[index].weight > css.weight { + self.stylesheets.remove(index); + self.stylesheets.push(css); + }, + _ => self.stylesheets.push(css) + } + self + } + + pub fn add_javascript(&mut self, js: JavaScript) -> &mut Self { + match self.javascripts.iter().position(|x| x.source == js.source) { + Some(index) => if self.javascripts[index].weight > js.weight { + self.javascripts.remove(index); + self.javascripts.push(js); + }, + _ => self.javascripts.push(js) + } + self + } + + pub fn add_jquery(&mut self) -> &mut Self { + if !self.with_jquery { + self.add_javascript( + JavaScript::source( + "/theme/js/jquery.min.js?ver=3.6.0" + ) + .with_weight(isize::MIN) + .with_mode(JSMode::Normal) + ); + self.with_jquery = true; + } + self + } + + /// Context GETTERS. + + pub(crate) fn theme(&mut self) -> &'static dyn ThemeTrait { + self.theme + } + + /// Context RENDER. + + pub fn render(&mut self) -> Markup { + let ordered_css = &mut self.stylesheets; + ordered_css.sort_by_key(|o| o.weight); + + let ordered_js = &mut self.javascripts; + ordered_js.sort_by_key(|o| o.weight); + + html! { + @match &self.favicon { + Some(favicon) => (favicon.render()), + None => "", + } + @for (name, content) in &self.metadata { + meta name=(name) content=(content) {} + } + @for css in ordered_css { + (css.render()) + } + @for js in ordered_js { + (js.render()) + } + } + } + + // Context EXTRAS. + + pub fn required_id(&mut self, id: &Option) -> String { + match id { + Some(id) => id.to_string(), + None => { + let prefix = util::single_type_name::() + .trim() + .replace(" ", "_") + .to_lowercase(); + let prefix = if prefix.is_empty() { + "prefix".to_owned() + } else { + prefix + }; + self.id_counter += 1; + concat_string!(prefix, "-", self.id_counter.to_string()) + } + } + } +} diff --git a/pagetop/src/core/component/context/favicon.rs b/pagetop/src/core/component/context/favicon.rs new file mode 100644 index 00000000..1788540e --- /dev/null +++ b/pagetop/src/core/component/context/favicon.rs @@ -0,0 +1,86 @@ +use crate::html::{Markup, PreEscaped, html}; + +pub struct Favicon(Vec); + +impl Favicon { + pub fn new() -> Self { + Favicon(Vec::new()) + } + + pub fn with_icon(self, image: &str) -> Self { + self.add_item("icon", image, "", "") + } + + pub fn with_icon_for_sizes(self, image: &str, sizes: &str) -> Self { + self.add_item("icon", image, sizes, "") + } + + pub fn with_apple_touch_icon(self, image: &str, sizes: &str) -> Self { + self.add_item("apple-touch-icon", image, sizes, "") + } + + pub fn with_mask_icon(self, image: &str, color: &str) -> Self { + self.add_item("mask-icon", image, "", color) + } + + pub fn with_manifest(self, file: &str) -> Self { + self.add_item("manifest", file, "", "") + } + + pub fn with_theme_color(mut self, color: &str) -> Self { + self.0.push(format!( + "", color + )); + self + } + + pub fn with_ms_tile_color(mut self, color: &str) -> Self { + self.0.push(format!( + "", color + )); + self + } + + pub fn with_ms_tile_image(mut self, image: &str) -> Self { + self.0.push(format!( + "", image + )); + self + } + + fn add_item( + mut self, + rel : &str, + source: &str, + sizes : &str, + color : &str + ) -> Self { + let mut link: String = format!(" format!("{} type=\"image/gif\"", link), + ".ico" => format!("{} type=\"image/x-icon\"", link), + ".jpg" => format!("{} type=\"image/jpg\"", link), + ".png" => format!("{} type=\"image/png\"", link), + ".svg" => format!("{} type=\"image/svg+xml\"", link), + _ => link + }; + } + if !sizes.is_empty() { + link = format!("{} sizes=\"{}\"", link, sizes); + } + if !color.is_empty() { + link = format!("{} color=\"{}\"", link, color); + } + self.0.push(format!("{} href=\"{}\">", link, source)); + self + } + + pub(super) fn render(&self) -> Markup { + html! { + @for item in &self.0 { + (PreEscaped(item)) + } + } + } +} diff --git a/pagetop/src/core/component/context/javascript.rs b/pagetop/src/core/component/context/javascript.rs new file mode 100644 index 00000000..2f2d725b --- /dev/null +++ b/pagetop/src/core/component/context/javascript.rs @@ -0,0 +1,43 @@ +use crate::html::{Markup, html}; + +#[derive(PartialEq)] +pub enum JSMode { Async, Defer, Normal } + +pub struct JavaScript { + pub(super) source: &'static str, + pub(super) weight: isize, + pub(super) mode : JSMode, +} +impl JavaScript { + pub fn source(s: &'static str) -> Self { + JavaScript { + source: s, + weight: 0, + mode : JSMode::Defer, + } + } + + pub fn with_weight(mut self, weight: isize) -> Self { + self.weight = weight; + self + } + + pub fn with_mode(mut self, mode: JSMode) -> Self { + self.mode = mode; + self + } + + pub fn weight(self) -> isize { + self.weight + } + + pub(super) fn render(&self) -> Markup { + html! { + script type="text/javascript" + src=(self.source) + async[self.mode == JSMode::Async] + defer[self.mode == JSMode::Defer] + {}; + } + } +} diff --git a/pagetop/src/core/component/context/stylesheet.rs b/pagetop/src/core/component/context/stylesheet.rs new file mode 100644 index 00000000..f7803938 --- /dev/null +++ b/pagetop/src/core/component/context/stylesheet.rs @@ -0,0 +1,29 @@ +use crate::html::{Markup, html}; + +pub struct StyleSheet { + pub(super) source: &'static str, + pub(super) weight: isize, +} +impl StyleSheet { + pub fn source(s: &'static str) -> Self { + StyleSheet { + source: s, + weight: 0, + } + } + + pub fn with_weight(mut self, weight: isize) -> Self { + self.weight = weight; + self + } + + pub fn weight(self) -> isize { + self.weight + } + + pub(super) fn render(&self) -> Markup { + html! { + link rel="stylesheet" href=(self.source); + } + } +} diff --git a/pagetop/src/core/component/definition.rs b/pagetop/src/core/component/definition.rs index 45fa3e91..ce57b240 100644 --- a/pagetop/src/core/component/definition.rs +++ b/pagetop/src/core/component/definition.rs @@ -1,8 +1,7 @@ use crate::util; use crate::html::{Markup, html}; use crate::core::hook::{hook_ref, run_hooks}; -use super::{BEFORE_RENDER_COMPONENT_HOOK, BeforeRenderComponentHook}; -use super::Assets; +use super::{BEFORE_RENDER_COMPONENT_HOOK, BeforeRenderComponentHook, Context}; pub use std::any::Any as AnyComponent; @@ -28,11 +27,11 @@ pub trait ComponentTrait: AnyComponent + Send + Sync { } #[allow(unused_variables)] - fn before_render(&mut self, assets: &mut Assets) { + fn before_render(&mut self, context: &mut Context) { } #[allow(unused_variables)] - fn default_render(&self, assets: &mut Assets) -> Markup { + fn default_render(&self, context: &mut Context) -> Markup { html! {} } @@ -49,24 +48,24 @@ pub fn component_mut(component: &mut dyn ComponentTrait) -> &mut C { component.as_mut_any().downcast_mut::().unwrap() } -pub fn render_component(component: &mut dyn ComponentTrait, assets: &mut Assets) -> Markup { +pub fn render_component(component: &mut dyn ComponentTrait, context: &mut Context) -> Markup { // Acciones del componente antes de renderizar. - component.before_render(assets); + component.before_render(context); // Acciones de los módulos antes de renderizar el componente. run_hooks( BEFORE_RENDER_COMPONENT_HOOK, - |a| hook_ref::(&**a).run(component, assets) + |a| hook_ref::(&**a).run(component, context) ); // Acciones del tema antes de renderizar el componente. - assets.theme().before_render_component(component, assets); + context.theme().before_render_component(component, context); match component.is_renderable() { true => { - match assets.theme().render_component(component, assets) { + match context.theme().render_component(component, context) { Some(html) => html, - None => component.default_render(assets) + None => component.default_render(context) } }, false => html! {} diff --git a/pagetop/src/core/component/holder.rs b/pagetop/src/core/component/holder.rs index 51b67736..b19eb7f2 100644 --- a/pagetop/src/core/component/holder.rs +++ b/pagetop/src/core/component/holder.rs @@ -1,5 +1,5 @@ use crate::html::{Markup, html}; -use super::{Assets, ComponentTrait}; +use super::{Context, ComponentTrait}; use std::sync::{Arc, RwLock}; @@ -21,12 +21,12 @@ impl ComponentsHolder { self.0.push(Arc::new(RwLock::new(component))); } - pub fn render(&self, assets: &mut Assets) -> Markup { + pub fn render(&self, context: &mut Context) -> Markup { let mut components = self.0.clone(); components.sort_by_key(|c| c.read().unwrap().weight()); html! { @for c in components.iter() { - (super::render_component(&mut *c.write().unwrap(), assets)) + (super::render_component(&mut *c.write().unwrap(), context)) } } } diff --git a/pagetop/src/core/component/hook.rs b/pagetop/src/core/component/hook.rs index f52d755b..e29ac1eb 100644 --- a/pagetop/src/core/component/hook.rs +++ b/pagetop/src/core/component/hook.rs @@ -1,10 +1,10 @@ use crate::core::hook::{HookTrait, AnyHook}; -use super::{Assets, ComponentTrait}; +use super::{ComponentTrait, Context}; pub const BEFORE_RENDER_COMPONENT_HOOK: &str = "pagetop::hook::before_render_component"; pub struct BeforeRenderComponentHook { - hook: Option, + hook: Option, weight: isize, } @@ -30,7 +30,7 @@ impl HookTrait for BeforeRenderComponentHook { } impl BeforeRenderComponentHook { - pub fn with_hook(mut self, hook: fn(&mut dyn ComponentTrait, &mut Assets)) -> Self { + pub fn with_hook(mut self, hook: fn(&mut dyn ComponentTrait, &mut Context)) -> Self { self.hook = Some(hook); self } @@ -40,9 +40,9 @@ impl BeforeRenderComponentHook { self } - pub fn run(&self, component: &mut dyn ComponentTrait, assets: &mut Assets) { + pub fn run(&self, component: &mut dyn ComponentTrait, context: &mut Context) { if let Some(hook) = self.hook { - hook(component, assets) + hook(component, context) } } } diff --git a/pagetop/src/core/theme/definition.rs b/pagetop/src/core/theme/definition.rs index 74457e19..205ea6cd 100644 --- a/pagetop/src/core/theme/definition.rs +++ b/pagetop/src/core/theme/definition.rs @@ -2,7 +2,7 @@ use crate::{concat_string, util}; use crate::config::SETTINGS; use crate::html::{Markup, html}; use crate::core::app; -use crate::core::component::{Assets, ComponentTrait, Favicon}; +use crate::core::component::{ComponentTrait, Context, Favicon}; use crate::response::page::Page; use crate::base::component::Chunck; @@ -28,7 +28,7 @@ pub trait ThemeTrait: BaseTheme + Send + Sync { #[allow(unused_variables)] fn before_render_page(&self, page: &mut Page) { - page.assets() + page.context() .with_favicon( Favicon::new() .with_icon("/theme/favicon.png") @@ -56,7 +56,7 @@ pub trait ThemeTrait: BaseTheme + Send + Sync { meta http-equiv="X-UA-Compatible" content="IE=edge"; meta name="viewport" content=(viewport); - (page.assets().render()) + (page.context().render()) } } } @@ -86,7 +86,7 @@ pub trait ThemeTrait: BaseTheme + Send + Sync { fn before_render_component( &self, component: &mut dyn ComponentTrait, - assets: &mut Assets + context: &mut Context ) { /* Cómo usarlo: @@ -105,7 +105,7 @@ pub trait ThemeTrait: BaseTheme + Send + Sync { fn render_component( &self, component: &dyn ComponentTrait, - assets: &mut Assets + context: &mut Context ) -> Option { None /* diff --git a/pagetop/src/response/page/definition.rs b/pagetop/src/response/page/definition.rs index 6febf1ac..f57de4ee 100644 --- a/pagetop/src/response/page/definition.rs +++ b/pagetop/src/response/page/definition.rs @@ -42,7 +42,7 @@ pub struct Page<'a> { direction : OptAttr, title : OptAttr, description : OptAttr, - assets : Assets, + context : Context, regions : HashMap<&'a str, ComponentsHolder>, body_classes: Classes, template : String, @@ -62,7 +62,7 @@ impl<'a> Page<'a> { }, title : OptAttr::new(), description : OptAttr::new(), - assets : Assets::new(), + context : Context::new(), regions : common_components(), body_classes: Classes::new_with_default("body"), template : "default".to_owned(), @@ -136,8 +136,8 @@ impl<'a> Page<'a> { self.description.option() } - pub fn assets(&mut self) -> &mut Assets { - &mut self.assets + pub fn context(&mut self) -> &mut Context { + &mut self.context } pub fn body_classes(&self) -> &Option { @@ -158,13 +158,13 @@ impl<'a> Page<'a> { ); // Acciones del tema antes de renderizar la página. - self.assets.theme().before_render_page(self); + self.context.theme().before_render_page(self); // Primero, renderizar el cuerpo. - let body = self.assets.theme().render_page_body(self); + let body = self.context.theme().render_page_body(self); // Luego, renderizar la cabecera. - let head = self.assets.theme().render_page_head(self); + let head = self.context.theme().render_page_head(self); // Finalmente, renderizar la página. return Ok(html! { @@ -178,7 +178,7 @@ impl<'a> Page<'a> { pub fn render_region(&mut self, region: &str) -> Markup { match self.regions.get_mut(region) { - Some(components) => components.render(&mut self.assets), + Some(components) => components.render(&mut self.context), None => html! {} } } @@ -186,7 +186,7 @@ impl<'a> Page<'a> { // Page EXTRAS. pub fn using_theme(&mut self, theme_name: &str) -> &mut Self { - self.assets.using_theme(theme_name); + self.context.using_theme(theme_name); self } }