diff --git a/pagetop-megamenu/src/component/item.rs b/pagetop-megamenu/src/component/item.rs index 8e5e8101..52c50d36 100644 --- a/pagetop-megamenu/src/component/item.rs +++ b/pagetop-megamenu/src/component/item.rs @@ -4,8 +4,8 @@ use crate::component::MegaMenu; new_handle!(COMPONENT_MEGAITEM); -type Label = OneComponent; -type Content = OneComponent; +type Label = ComponentOne; +type Content = ComponentOne; #[derive(Default)] pub enum MegaItemType { diff --git a/pagetop-megamenu/src/component/menu.rs b/pagetop-megamenu/src/component/menu.rs index 6ce6239e..819d0d0b 100644 --- a/pagetop-megamenu/src/component/menu.rs +++ b/pagetop-megamenu/src/component/menu.rs @@ -26,7 +26,7 @@ pub struct MegaMenu { weight : Weight, renderable: Renderable, id : IdentifierValue, - items : PackComponents, + items : VeckComponents, theme : MegaMenuTheme, } @@ -153,12 +153,13 @@ impl MegaMenu { } pub fn with_item(mut self, item: MegaItem) -> Self { - self.items.alter(PackOp::Add, ComponentArc::new(item)); + self.items.alter(VeckOp::Add(ComponentOne::with(item))); self } - pub fn alter_items(&mut self, op: PackOp, item: MegaItem) -> &mut Self { - self.items.alter(op, ComponentArc::new(item)); + #[fn_builder] + pub fn alter_items(&mut self, op: VeckOp) -> &mut Self { + self.items.alter(op); self } @@ -170,7 +171,7 @@ impl MegaMenu { // MegaMenu GETTERS. - pub fn items(&self) -> &PackComponents { + pub fn items(&self) -> &VeckComponents { &self.items } diff --git a/pagetop-minimal/src/component/anchor.rs b/pagetop-minimal/src/component/anchor.rs index 58b1a566..709ab28e 100644 --- a/pagetop-minimal/src/component/anchor.rs +++ b/pagetop-minimal/src/component/anchor.rs @@ -22,8 +22,8 @@ pub enum AnchorTarget { Context(String), } -type AnchorIcon = OneComponent; -type AnchorHtml = OneComponent; +type AnchorIcon = ComponentOne; +type AnchorHtml = ComponentOne; #[rustfmt::skip] #[derive(Default)] diff --git a/pagetop-minimal/src/component/block.rs b/pagetop-minimal/src/component/block.rs index bc7bc440..d7ffe41c 100644 --- a/pagetop-minimal/src/component/block.rs +++ b/pagetop-minimal/src/component/block.rs @@ -94,17 +94,13 @@ impl Block { } pub fn with_component(mut self, component: impl ComponentTrait) -> Self { - self.stuff.alter(PackOp::Add, ComponentArc::new(component)); + self.stuff.alter(PackOp::Add(ComponentArc::with(component))); self } - pub fn with_component_arc(mut self, arc: ComponentArc) -> Self { - self.stuff.alter(PackOp::Add, arc); - self - } - - pub fn alter_components(&mut self, op: PackOp, component: impl ComponentTrait) -> &mut Self { - self.stuff.alter(op, ComponentArc::new(component)); + #[fn_builder] + pub fn alter_components(&mut self, op: PackOp) -> &mut Self { + self.stuff.alter(op); self } diff --git a/pagetop-minimal/src/component/container.rs b/pagetop-minimal/src/component/container.rs index b3c79f4a..3a99eb56 100644 --- a/pagetop-minimal/src/component/container.rs +++ b/pagetop-minimal/src/component/container.rs @@ -155,17 +155,13 @@ impl Container { } pub fn with_component(mut self, component: impl ComponentTrait) -> Self { - self.stuff.alter(PackOp::Add, ComponentArc::new(component)); + self.stuff.alter(PackOp::Add(ComponentArc::with(component))); self } - pub fn with_component_arc(mut self, arc: ComponentArc) -> Self { - self.stuff.alter(PackOp::Add, arc); - self - } - - pub fn alter_components(&mut self, op: PackOp, component: impl ComponentTrait) -> &mut Self { - self.stuff.alter(op, ComponentArc::new(component)); + #[fn_builder] + pub fn alter_components(&mut self, op: PackOp) -> &mut Self { + self.stuff.alter(op); self } diff --git a/pagetop-minimal/src/component/flex/container.rs b/pagetop-minimal/src/component/flex/container.rs index 8858c286..803ad6ab 100644 --- a/pagetop-minimal/src/component/flex/container.rs +++ b/pagetop-minimal/src/component/flex/container.rs @@ -13,7 +13,7 @@ pub struct Container { renderable: Renderable, id : IdentifierValue, classes : Classes, - items : PackComponents, + items : VeckComponents, template : String, } @@ -83,12 +83,13 @@ impl Container { } pub fn with_item(mut self, item: flex::Item) -> Self { - self.items.alter(PackOp::Add, ComponentArc::new(item)); + self.items.alter(VeckOp::Add(ComponentOne::with(item))); self } - pub fn alter_items(&mut self, op: PackOp, item: flex::Item) -> &mut Self { - self.items.alter(op, ComponentArc::new(item)); + #[fn_builder] + pub fn alter_items(&mut self, op: VeckOp) -> &mut Self { + self.items.alter(op); self } @@ -104,7 +105,7 @@ impl Container { &self.classes } - pub fn items(&self) -> &PackComponents { + pub fn items(&self) -> &VeckComponents { &self.items } diff --git a/pagetop-minimal/src/component/flex/item.rs b/pagetop-minimal/src/component/flex/item.rs index 7dae7b6f..164ff2aa 100644 --- a/pagetop-minimal/src/component/flex/item.rs +++ b/pagetop-minimal/src/component/flex/item.rs @@ -136,17 +136,13 @@ impl Item { } pub fn with_component(mut self, component: impl ComponentTrait) -> Self { - self.stuff.alter(PackOp::Add, ComponentArc::new(component)); + self.stuff.alter(PackOp::Add(ComponentArc::with(component))); self } - pub fn with_component_arc(mut self, arc: ComponentArc) -> Self { - self.stuff.alter(PackOp::Add, arc); - self - } - - pub fn alter_components(&mut self, op: PackOp, component: impl ComponentTrait) -> &mut Self { - self.stuff.alter(op, ComponentArc::new(component)); + #[fn_builder] + pub fn alter_components(&mut self, op: PackOp) -> &mut Self { + self.stuff.alter(op); self } diff --git a/pagetop-minimal/src/component/form_element/button.rs b/pagetop-minimal/src/component/form_element/button.rs index c34dbdfd..d2683c03 100644 --- a/pagetop-minimal/src/component/form_element/button.rs +++ b/pagetop-minimal/src/component/form_element/button.rs @@ -10,7 +10,7 @@ pub enum ButtonType { Reset, } -type ButtonValue = OneComponent; +type ButtonValue = ComponentOne; #[rustfmt::skip] #[derive(Default)] diff --git a/pagetop-minimal/src/component/form_element/form.rs b/pagetop-minimal/src/component/form_element/form.rs index 1290e9da..ef8d403d 100644 --- a/pagetop-minimal/src/component/form_element/form.rs +++ b/pagetop-minimal/src/component/form_element/form.rs @@ -21,7 +21,7 @@ pub struct Form { action : AttributeValue, charset : AttributeValue, method : FormMethod, - elements : PackComponents, + stuff : PackComponents, template : String, } @@ -121,17 +121,13 @@ impl Form { } pub fn with_element(mut self, element: impl ComponentTrait) -> Self { - self.elements.alter(PackOp::Add, ComponentArc::new(element)); + self.stuff.alter(PackOp::Add(ComponentArc::with(element))); self } - pub fn with_element_arc(mut self, arc: ComponentArc) -> Self { - self.elements.alter(PackOp::Add, arc); - self - } - - pub fn alter_elements(&mut self, op: PackOp, element: impl ComponentTrait) -> &mut Self { - self.elements.alter(op, ComponentArc::new(element)); + #[fn_builder] + pub fn alter_elements(&mut self, op: PackOp) -> &mut Self { + self.stuff.alter(op); self } @@ -160,7 +156,7 @@ impl Form { } pub fn elements(&self) -> &PackComponents { - &self.elements + &self.stuff } pub fn template(&self) -> &str { diff --git a/pagetop-minimal/src/component/form_element/input.rs b/pagetop-minimal/src/component/form_element/input.rs index aaf230dc..a295eb7f 100644 --- a/pagetop-minimal/src/component/form_element/input.rs +++ b/pagetop-minimal/src/component/form_element/input.rs @@ -13,8 +13,8 @@ pub enum InputType { Url, } -type InputLabel = OneComponent; -type InputHelpText = OneComponent; +type InputLabel = ComponentOne; +type InputHelpText = ComponentOne; #[rustfmt::skip] #[derive(Default)] diff --git a/pagetop-minimal/src/component/grid/column.rs b/pagetop-minimal/src/component/grid/column.rs index f701af96..ef4ba1a7 100644 --- a/pagetop-minimal/src/component/grid/column.rs +++ b/pagetop-minimal/src/component/grid/column.rs @@ -136,17 +136,13 @@ impl Column { } pub fn with_component(mut self, component: impl ComponentTrait) -> Self { - self.stuff.alter(PackOp::Add, ComponentArc::new(component)); + self.stuff.alter(PackOp::Add(ComponentArc::with(component))); self } - pub fn with_component_arc(mut self, arc: ComponentArc) -> Self { - self.stuff.alter(PackOp::Add, arc); - self - } - - pub fn alter_components(&mut self, op: PackOp, component: impl ComponentTrait) -> &mut Self { - self.stuff.alter(op, ComponentArc::new(component)); + #[fn_builder] + pub fn alter_components(&mut self, op: PackOp) -> &mut Self { + self.stuff.alter(op); self } diff --git a/pagetop-minimal/src/component/grid/row.rs b/pagetop-minimal/src/component/grid/row.rs index 5c261a89..5b60ad80 100644 --- a/pagetop-minimal/src/component/grid/row.rs +++ b/pagetop-minimal/src/component/grid/row.rs @@ -13,7 +13,7 @@ pub struct Row { renderable: Renderable, id : IdentifierValue, classes : Classes, - columns : PackComponents, + columns : VeckComponents, template : String, } @@ -83,12 +83,13 @@ impl Row { } pub fn with_column(mut self, column: grid::Column) -> Self { - self.columns.alter(PackOp::Add, ComponentArc::new(column)); + self.columns.alter(VeckOp::Add(ComponentOne::with(column))); self } - pub fn alter_columns(&mut self, op: PackOp, column: grid::Column) -> &mut Self { - self.columns.alter(op, ComponentArc::new(column)); + #[fn_builder] + pub fn alter_columns(&mut self, op: VeckOp) -> &mut Self { + self.columns.alter(op); self } @@ -104,7 +105,7 @@ impl Row { &self.classes } - pub fn columns(&self) -> &PackComponents { + pub fn columns(&self) -> &VeckComponents { &self.columns } diff --git a/pagetop-minimal/src/component/heading.rs b/pagetop-minimal/src/component/heading.rs index d6f15ff7..b0a6afb5 100644 --- a/pagetop-minimal/src/component/heading.rs +++ b/pagetop-minimal/src/component/heading.rs @@ -25,7 +25,7 @@ pub enum HeadingDisplay { Subtitle, } -type HeadingText = OneComponent; +type HeadingText = ComponentOne; #[rustfmt::skip] #[derive(Default)] diff --git a/pagetop-minimal/src/component/paragraph.rs b/pagetop-minimal/src/component/paragraph.rs index a88f07a7..ecffc048 100644 --- a/pagetop-minimal/src/component/paragraph.rs +++ b/pagetop-minimal/src/component/paragraph.rs @@ -90,17 +90,13 @@ impl Paragraph { } pub fn with_component(mut self, component: impl ComponentTrait) -> Self { - self.stuff.alter(PackOp::Add, ComponentArc::new(component)); + self.stuff.alter(PackOp::Add(ComponentArc::with(component))); self } - pub fn with_component_arc(mut self, arc: ComponentArc) -> Self { - self.stuff.alter(PackOp::Add, arc); - self - } - - pub fn alter_components(&mut self, op: PackOp, component: impl ComponentTrait) -> &mut Self { - self.stuff.alter(op, ComponentArc::new(component)); + #[fn_builder] + pub fn alter_components(&mut self, op: PackOp) -> &mut Self { + self.stuff.alter(op); self } diff --git a/pagetop-minimal/src/component/site_branding.rs b/pagetop-minimal/src/component/site_branding.rs index 5e3ab340..824f011b 100644 --- a/pagetop-minimal/src/component/site_branding.rs +++ b/pagetop-minimal/src/component/site_branding.rs @@ -6,8 +6,8 @@ use crate::LOCALES_MINIMAL; new_handle!(COMPONENT_BRANDING); -type SiteSlogan = OneComponent; -type SiteLogo = OneComponent; +type SiteSlogan = ComponentOne; +type SiteLogo = ComponentOne; #[rustfmt::skip] pub struct SiteBranding { diff --git a/pagetop/src/core/component.rs b/pagetop/src/core/component.rs index 179514d9..3d2bb8f1 100644 --- a/pagetop/src/core/component.rs +++ b/pagetop/src/core/component.rs @@ -5,17 +5,20 @@ pub type FnContextualPath = fn(cx: &Context) -> &str; mod definition; pub use definition::{component_as_mut, component_as_ref, ComponentBase, ComponentTrait}; +mod renderable; +pub use renderable::{FnIsRenderable, Renderable}; + mod arc; pub use arc::ComponentArc; -mod one; -pub use one::OneComponent; - mod pack; pub use pack::{PackComponents, PackOp}; -mod renderable; -pub use renderable::{FnIsRenderable, Renderable}; +mod one; +pub use one::ComponentOne; + +mod veck; +pub use veck::{VeckComponents, VeckOp}; pub mod html; pub mod l10n; diff --git a/pagetop/src/core/component/arc.rs b/pagetop/src/core/component/arc.rs index 93e1193c..734248cb 100644 --- a/pagetop/src/core/component/arc.rs +++ b/pagetop/src/core/component/arc.rs @@ -1,14 +1,39 @@ use crate::core::component::{ComponentTrait, Context}; use crate::html::Markup; -use crate::{Handle, Weight}; +use crate::{new_handle, Handle, Weight}; use std::sync::{Arc, RwLock}; +new_handle!(COMPONENT_NULL for Crate); + +#[derive(Default)] +struct ComponentNull; + +impl ComponentTrait for ComponentNull { + fn new() -> Self { + ComponentNull::default() + } + + fn handle(&self) -> Handle { + COMPONENT_NULL + } +} + #[derive(Clone)] pub struct ComponentArc(Arc>); +impl Default for ComponentArc { + fn default() -> Self { + ComponentArc(Arc::new(RwLock::new(ComponentNull))) + } +} + impl ComponentArc { - pub fn new(component: impl ComponentTrait) -> Self { + pub fn new() -> Self { + ComponentArc::default() + } + + pub fn with(component: impl ComponentTrait) -> Self { ComponentArc(Arc::new(RwLock::new(component))) } @@ -24,7 +49,9 @@ impl ComponentArc { self.0.read().unwrap().weight() } - pub(crate) fn prepare(&self, cx: &mut Context) -> Markup { + // ComponentArc PREPARE. + + pub fn prepare(&self, cx: &mut Context) -> Markup { self.0.write().unwrap().prepare(cx) } } diff --git a/pagetop/src/core/component/one.rs b/pagetop/src/core/component/one.rs index f0d31ef5..cc05bac4 100644 --- a/pagetop/src/core/component/one.rs +++ b/pagetop/src/core/component/one.rs @@ -1,30 +1,46 @@ use crate::core::component::{ComponentTrait, Context}; -use crate::html::{html, Markup}; +use crate::html::Markup; +use crate::{Handle, Weight}; use std::sync::{Arc, RwLock}; -#[derive(Clone, Default)] -pub struct OneComponent(Option>>); +#[derive(Default)] +pub struct ComponentOne(Arc>); -impl OneComponent { +impl Clone for ComponentOne { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} + +impl ComponentOne { pub fn new() -> Self { - OneComponent::::default() + ComponentOne::::default() } pub fn with(component: T) -> Self { - OneComponent(Some(Arc::new(RwLock::new(component)))) + ComponentOne(Arc::new(RwLock::new(component))) } pub fn set(&mut self, component: T) { - self.0 = Some(Arc::new(RwLock::new(component))); + self.0 = Arc::new(RwLock::new(component)); } - // OneComponent PREPARE. + pub(crate) fn handle(&self) -> Handle { + self.0.read().unwrap().handle() + } + + pub(crate) fn id(&self) -> Option { + self.0.read().unwrap().id() + } + + pub(crate) fn weight(&self) -> Weight { + self.0.read().unwrap().weight() + } + + // ComponentOne PREPARE. pub fn prepare(&self, cx: &mut Context) -> Markup { - if let Some(component) = &self.0 { - return component.write().unwrap().prepare(cx); - } - html! {} + self.0.write().unwrap().prepare(cx) } } diff --git a/pagetop/src/core/component/pack.rs b/pagetop/src/core/component/pack.rs index e55799c9..f9b16cf9 100644 --- a/pagetop/src/core/component/pack.rs +++ b/pagetop/src/core/component/pack.rs @@ -3,12 +3,12 @@ use crate::html::{html, Markup}; use crate::Handle; pub enum PackOp { - Add, - AddAfterId(&'static str), - AddBeforeId(&'static str), - AddFirst, + Add(ComponentArc), + AddAfterId(&'static str, ComponentArc), + AddBeforeId(&'static str, ComponentArc), + AddFirst(ComponentArc), RemoveById(&'static str), - ReplaceById(&'static str), + ReplaceById(&'static str, ComponentArc), Reset, } @@ -22,7 +22,7 @@ impl PackComponents { pub fn with(arc: ComponentArc) -> Self { let mut pack = PackComponents::new(); - pack.alter(PackOp::Add, arc); + pack.alter(PackOp::Add(arc)); pack } @@ -36,28 +36,28 @@ impl PackComponents { // PackComponents BUILDER. - pub fn alter(&mut self, op: PackOp, arc: ComponentArc) -> &mut Self { + pub fn alter(&mut self, op: PackOp) -> &mut Self { match op { - PackOp::Add => self.0.push(arc), - PackOp::AddAfterId(id) => { + PackOp::Add(arc) => self.0.push(arc), + PackOp::AddAfterId(id, arc) => { match self.0.iter().position(|c| c.id().as_deref() == Some(id)) { Some(index) => self.0.insert(index + 1, arc), _ => self.0.push(arc), } } - PackOp::AddBeforeId(id) => { + PackOp::AddBeforeId(id, arc) => { match self.0.iter().position(|c| c.id().as_deref() == Some(id)) { Some(index) => self.0.insert(index, arc), _ => self.0.insert(0, arc), } } - PackOp::AddFirst => self.0.insert(0, arc), + PackOp::AddFirst(arc) => self.0.insert(0, arc), PackOp::RemoveById(id) => { if let Some(index) = self.0.iter().position(|c| c.id().as_deref() == Some(id)) { self.0.remove(index); } } - PackOp::ReplaceById(id) => { + PackOp::ReplaceById(id, arc) => { for c in self.0.iter_mut() { if c.id().as_deref() == Some(id) { *c = arc; diff --git a/pagetop/src/core/component/veck.rs b/pagetop/src/core/component/veck.rs new file mode 100644 index 00000000..9ba9426c --- /dev/null +++ b/pagetop/src/core/component/veck.rs @@ -0,0 +1,90 @@ +use crate::core::component::{ComponentOne, ComponentTrait, Context}; +use crate::html::{html, Markup}; +use crate::Handle; + +pub enum VeckOp { + Add(ComponentOne), + AddAfterId(&'static str, ComponentOne), + AddBeforeId(&'static str, ComponentOne), + AddFirst(ComponentOne), + RemoveById(&'static str), + ReplaceById(&'static str, ComponentOne), + Reset, +} + +#[derive(Clone, Default)] +pub struct VeckComponents(Vec>); + +impl VeckComponents { + pub fn new() -> Self { + VeckComponents::::default() + } + + pub fn with(one: ComponentOne) -> Self { + let mut veck = VeckComponents::new(); + veck.alter(VeckOp::Add(one)); + veck + } + + // VeckComponents BUILDER. + + pub fn alter(&mut self, op: VeckOp) -> &mut Self { + match op { + VeckOp::Add(one) => self.0.push(one), + VeckOp::AddAfterId(id, one) => { + match self.0.iter().position(|c| c.id().as_deref() == Some(id)) { + Some(index) => self.0.insert(index + 1, one), + _ => self.0.push(one), + } + } + VeckOp::AddBeforeId(id, one) => { + match self.0.iter().position(|c| c.id().as_deref() == Some(id)) { + Some(index) => self.0.insert(index, one), + _ => self.0.insert(0, one), + } + } + VeckOp::AddFirst(one) => self.0.insert(0, one), + VeckOp::RemoveById(id) => { + if let Some(index) = self.0.iter().position(|c| c.id().as_deref() == Some(id)) { + self.0.remove(index); + } + } + VeckOp::ReplaceById(id, one) => { + for c in self.0.iter_mut() { + if c.id().as_deref() == Some(id) { + *c = one; + break; + } + } + } + VeckOp::Reset => self.0.clear(), + } + self + } + + // VeckComponents GETTERS. + + pub fn get_by_id(&self, id: &'static str) -> Option<&ComponentOne> { + self.0.iter().find(|&c| c.id().as_deref() == Some(id)) + } + + pub fn iter_by_id(&self, id: &'static str) -> impl Iterator> { + self.0.iter().filter(|&c| c.id().as_deref() == Some(id)) + } + + pub fn iter_by_handle(&self, handle: Handle) -> impl Iterator> { + self.0.iter().filter(move |&c| c.handle() == handle) + } + + // VeckComponents PREPARE. + + pub fn prepare(&self, cx: &mut Context) -> Markup { + let mut components = self.0.clone(); + components.sort_by_key(|c| c.weight()); + html! { + @for c in components.iter() { + " " (c.prepare(cx)) " " + } + } + } +} diff --git a/pagetop/src/core/theme/regions.rs b/pagetop/src/core/theme/regions.rs index 20aa99bd..9364f4d3 100644 --- a/pagetop/src/core/theme/regions.rs +++ b/pagetop/src/core/theme/regions.rs @@ -27,13 +27,13 @@ impl ComponentsRegions { pub fn add_in(&mut self, region: &'static str, arc: ComponentArc) { if let Some(region) = self.0.get_mut(region) { - region.alter(PackOp::Add, arc); + region.alter(PackOp::Add(arc)); } else { self.0.insert(region, PackComponents::with(arc)); } } - pub fn get_pack(&self, theme: ThemeRef, region: &str) -> PackComponents { + pub fn get_components(&self, theme: ThemeRef, region: &str) -> PackComponents { let common = COMMON_REGIONS.read().unwrap(); if let Some(hm) = THEME_REGIONS.read().unwrap().get(&theme.handle()) { PackComponents::merge(&[common.0.get(region), self.0.get(region), hm.0.get(region)]) diff --git a/pagetop/src/response/page.rs b/pagetop/src/response/page.rs index 86199984..cb1355bc 100644 --- a/pagetop/src/response/page.rs +++ b/pagetop/src/response/page.rs @@ -2,7 +2,7 @@ mod action; pub use action::*; use crate::core::component::l10n::L10n; -use crate::core::component::{ComponentArc, ComponentTrait, Context, ContextOp, OneComponent}; +use crate::core::component::{ComponentArc, ComponentOne, ComponentTrait, Context, ContextOp}; use crate::core::theme::ComponentsRegions; use crate::html::{html, Classes, ClassesOp, Favicon, Markup, DOCTYPE}; use crate::response::fatal_error::FatalError; @@ -12,8 +12,8 @@ use unic_langid::CharacterDirection; pub use actix_web::Result as ResultPage; -type PageTitle = OneComponent; -type PageDescription = OneComponent; +type PageTitle = ComponentOne; +type PageDescription = ComponentOne; #[rustfmt::skip] pub struct Page { @@ -90,7 +90,7 @@ impl Page { #[fn_builder] pub fn alter_in(&mut self, region: &'static str, component: impl ComponentTrait) -> &mut Self { - self.regions.add_in(region, ComponentArc::new(component)); + self.regions.add_in(region, ComponentArc::with(component)); self } @@ -173,7 +173,7 @@ impl Page { pub fn prepare_region(&mut self, region: &str) -> Option { let render = self .regions - .get_pack(self.context.theme(), region) + .get_components(self.context.theme(), region) .prepare(self.context()); if render.is_empty() { None