use crate::core::component::Context;
use crate::html::assets::Asset;
use crate::html::{html, Markup, PreEscaped};
use crate::{util, AutoDefault, CowStr, Weight};
#[derive(AutoDefault)]
enum Source {
#[default]
From(CowStr),
Defer(CowStr),
Async(CowStr),
Inline(CowStr, Box<dyn Fn(&mut Context) -> String + Send + Sync>),
OnLoad(CowStr, Box<dyn Fn(&mut Context) -> String + Send + Sync>),
OnLoadAsync(CowStr, Box<dyn Fn(&mut Context) -> String + Send + Sync>),
}
#[derive(AutoDefault)]
pub struct JavaScript {
source: Source, version: CowStr, weight: Weight, }
impl JavaScript {
pub fn from(path: impl Into<CowStr>) -> Self {
Self {
source: Source::From(path.into()),
..Default::default()
}
}
pub fn defer(path: impl Into<CowStr>) -> Self {
Self {
source: Source::Defer(path.into()),
..Default::default()
}
}
pub fn asynchronous(path: impl Into<CowStr>) -> Self {
Self {
source: Source::Async(path.into()),
..Default::default()
}
}
pub fn inline<F>(name: impl Into<CowStr>, f: F) -> Self
where
F: Fn(&mut Context) -> String + Send + Sync + 'static,
{
Self {
source: Source::Inline(name.into(), Box::new(f)),
..Default::default()
}
}
pub fn on_load<F>(name: impl Into<CowStr>, f: F) -> Self
where
F: Fn(&mut Context) -> String + Send + Sync + 'static,
{
Self {
source: Source::OnLoad(name.into(), Box::new(f)),
..Default::default()
}
}
pub fn on_load_async<F>(name: impl Into<CowStr>, f: F) -> Self
where
F: Fn(&mut Context) -> String + Send + Sync + 'static,
{
Self {
source: Source::OnLoadAsync(name.into(), Box::new(f)),
..Default::default()
}
}
pub fn with_version(mut self, version: impl Into<CowStr>) -> Self {
self.version = version.into();
self
}
pub fn with_weight(mut self, value: Weight) -> Self {
self.weight = value;
self
}
}
impl Asset for JavaScript {
fn name(&self) -> &str {
match &self.source {
Source::From(path) => path,
Source::Defer(path) => path,
Source::Async(path) => path,
Source::Inline(name, _) => name,
Source::OnLoad(name, _) => name,
Source::OnLoadAsync(name, _) => name,
}
}
fn weight(&self) -> Weight {
self.weight
}
fn render(&self, cx: &mut Context) -> Markup {
match &self.source {
Source::From(path) => html! {
script src=(util::join_pair!(path, "?v=", &self.version)) {};
},
Source::Defer(path) => html! {
script src=(util::join_pair!(path, "?v=", &self.version)) defer {};
},
Source::Async(path) => html! {
script src=(util::join_pair!(path, "?v=", &self.version)) async {};
},
Source::Inline(_, f) => html! {
script { (PreEscaped((f)(cx))) };
},
Source::OnLoad(_, f) => html! { script { (PreEscaped(util::join!(
"document.addEventListener(\"DOMContentLoaded\",function(){", (f)(cx), "});"
))) } },
Source::OnLoadAsync(_, f) => html! { script { (PreEscaped(util::join!(
"document.addEventListener(\"DOMContentLoaded\",async()=>{", (f)(cx), "});"
))) } },
}
}
}