use super::{ElementWithChildren, HtmlElement};
use crate::{
html::attribute::{Attribute, NextAttribute},
renderer::Rndr,
view::add_attr::AddAnyAttr,
};
use std::{future::Future, sync::Arc};
#[inline(always)]
pub fn inner_html<T>(value: T) -> InnerHtml<T>
where
T: InnerHtmlValue,
{
InnerHtml { value }
}
#[derive(Debug)]
pub struct InnerHtml<T> {
value: T,
}
impl<T> Clone for InnerHtml<T>
where
T: Clone,
{
fn clone(&self) -> Self {
Self {
value: self.value.clone(),
}
}
}
impl<T> Attribute for InnerHtml<T>
where
T: InnerHtmlValue,
{
const MIN_LENGTH: usize = 0;
type AsyncOutput = InnerHtml<T::AsyncOutput>;
type State = T::State;
type Cloneable = InnerHtml<T::Cloneable>;
type CloneableOwned = InnerHtml<T::CloneableOwned>;
fn html_len(&self) -> usize {
self.value.html_len()
}
fn to_html(
self,
_buf: &mut String,
_class: &mut String,
_style: &mut String,
inner_html: &mut String,
) {
self.value.to_html(inner_html);
}
fn hydrate<const FROM_SERVER: bool>(
self,
el: &crate::renderer::types::Element,
) -> Self::State {
self.value.hydrate::<FROM_SERVER>(el)
}
fn build(self, el: &crate::renderer::types::Element) -> Self::State {
self.value.build(el)
}
fn rebuild(self, state: &mut Self::State) {
self.value.rebuild(state);
}
fn into_cloneable(self) -> Self::Cloneable {
InnerHtml {
value: self.value.into_cloneable(),
}
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
InnerHtml {
value: self.value.into_cloneable_owned(),
}
}
fn dry_resolve(&mut self) {
self.value.dry_resolve();
}
async fn resolve(self) -> Self::AsyncOutput {
InnerHtml {
value: self.value.resolve().await,
}
}
}
impl<T> NextAttribute for InnerHtml<T>
where
T: InnerHtmlValue,
{
type Output<NewAttr: Attribute> = (Self, NewAttr);
fn add_any_attr<NewAttr: Attribute>(
self,
new_attr: NewAttr,
) -> Self::Output<NewAttr> {
(self, new_attr)
}
}
pub trait InnerHtmlAttribute<T>
where
T: InnerHtmlValue,
Self: Sized + AddAnyAttr,
{
fn inner_html(
self,
value: T,
) -> <Self as AddAnyAttr>::Output<InnerHtml<T>> {
self.add_any_attr(inner_html(value))
}
}
impl<T, E, At> InnerHtmlAttribute<T> for HtmlElement<E, At, ()>
where
Self: AddAnyAttr,
E: ElementWithChildren,
At: Attribute,
T: InnerHtmlValue,
{
fn inner_html(
self,
value: T,
) -> <Self as AddAnyAttr>::Output<InnerHtml<T>> {
self.add_any_attr(inner_html(value))
}
}
pub trait InnerHtmlValue: Send {
type AsyncOutput: InnerHtmlValue;
type State;
type Cloneable: InnerHtmlValue + Clone;
type CloneableOwned: InnerHtmlValue + Clone + 'static;
fn html_len(&self) -> usize;
fn to_html(self, buf: &mut String);
fn to_template(buf: &mut String);
fn hydrate<const FROM_SERVER: bool>(
self,
el: &crate::renderer::types::Element,
) -> Self::State;
fn build(self, el: &crate::renderer::types::Element) -> Self::State;
fn rebuild(self, state: &mut Self::State);
fn into_cloneable(self) -> Self::Cloneable;
fn into_cloneable_owned(self) -> Self::CloneableOwned;
fn dry_resolve(&mut self);
fn resolve(self) -> impl Future<Output = Self::AsyncOutput> + Send;
}
impl InnerHtmlValue for String {
type AsyncOutput = Self;
type State = (crate::renderer::types::Element, Self);
type Cloneable = Arc<str>;
type CloneableOwned = Arc<str>;
fn html_len(&self) -> usize {
self.len()
}
fn to_html(self, buf: &mut String) {
buf.push_str(&self);
}
fn to_template(_buf: &mut String) {}
fn hydrate<const FROM_SERVER: bool>(
self,
el: &crate::renderer::types::Element,
) -> Self::State {
if !FROM_SERVER {
Rndr::set_inner_html(el, &self);
}
(el.clone(), self)
}
fn build(self, el: &crate::renderer::types::Element) -> Self::State {
Rndr::set_inner_html(el, &self);
(el.clone(), self)
}
fn rebuild(self, state: &mut Self::State) {
if self != state.1 {
Rndr::set_inner_html(&state.0, &self);
state.1 = self;
}
}
fn into_cloneable(self) -> Self::Cloneable {
self.into()
}
fn into_cloneable_owned(self) -> Self::Cloneable {
self.into()
}
fn dry_resolve(&mut self) {}
async fn resolve(self) -> Self::AsyncOutput {
self
}
}
impl InnerHtmlValue for Arc<str> {
type AsyncOutput = Self;
type State = (crate::renderer::types::Element, Self);
type Cloneable = Self;
type CloneableOwned = Self;
fn html_len(&self) -> usize {
self.len()
}
fn to_html(self, buf: &mut String) {
buf.push_str(&self);
}
fn to_template(_buf: &mut String) {}
fn hydrate<const FROM_SERVER: bool>(
self,
el: &crate::renderer::types::Element,
) -> Self::State {
if !FROM_SERVER {
Rndr::set_inner_html(el, &self);
}
(el.clone(), self)
}
fn build(self, el: &crate::renderer::types::Element) -> Self::State {
Rndr::set_inner_html(el, &self);
(el.clone(), self)
}
fn rebuild(self, state: &mut Self::State) {
if !Arc::ptr_eq(&self, &state.1) {
Rndr::set_inner_html(&state.0, &self);
state.1 = self;
}
}
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::Cloneable {
self
}
fn dry_resolve(&mut self) {}
async fn resolve(self) -> Self::AsyncOutput {
self
}
}
impl<'a> InnerHtmlValue for &'a str {
type AsyncOutput = Self;
type State = (crate::renderer::types::Element, Self);
type Cloneable = Self;
type CloneableOwned = Arc<str>;
fn html_len(&self) -> usize {
self.len()
}
fn to_html(self, buf: &mut String) {
buf.push_str(self);
}
fn to_template(_buf: &mut String) {}
fn hydrate<const FROM_SERVER: bool>(
self,
el: &crate::renderer::types::Element,
) -> Self::State {
if !FROM_SERVER {
Rndr::set_inner_html(el, self);
}
(el.clone(), self)
}
fn build(self, el: &crate::renderer::types::Element) -> Self::State {
Rndr::set_inner_html(el, self);
(el.clone(), self)
}
fn rebuild(self, state: &mut Self::State) {
if self != state.1 {
Rndr::set_inner_html(&state.0, self);
state.1 = self;
}
}
fn into_cloneable(self) -> Self::Cloneable {
self
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.into()
}
fn dry_resolve(&mut self) {}
async fn resolve(self) -> Self::AsyncOutput {
self
}
}
impl<T> InnerHtmlValue for Option<T>
where
T: InnerHtmlValue,
{
type AsyncOutput = Self;
type State = (crate::renderer::types::Element, Option<T::State>);
type Cloneable = Option<T::Cloneable>;
type CloneableOwned = Option<T::CloneableOwned>;
fn html_len(&self) -> usize {
match self {
Some(i) => i.html_len(),
None => 0,
}
}
fn to_html(self, buf: &mut String) {
if let Some(value) = self {
value.to_html(buf);
}
}
fn to_template(_buf: &mut String) {}
fn hydrate<const FROM_SERVER: bool>(
self,
el: &crate::renderer::types::Element,
) -> Self::State {
(el.clone(), self.map(|n| n.hydrate::<FROM_SERVER>(el)))
}
fn build(self, el: &crate::renderer::types::Element) -> Self::State {
(el.clone(), self.map(|n| n.build(el)))
}
fn rebuild(self, state: &mut Self::State) {
let new_state = match (self, &mut state.1) {
(None, None) => None,
(None, Some(_)) => {
Rndr::set_inner_html(&state.0, "");
Some(None)
}
(Some(new), None) => Some(Some(new.build(&state.0))),
(Some(new), Some(state)) => {
new.rebuild(state);
None
}
};
if let Some(new_state) = new_state {
state.1 = new_state;
}
}
fn into_cloneable(self) -> Self::Cloneable {
self.map(|inner| inner.into_cloneable())
}
fn into_cloneable_owned(self) -> Self::CloneableOwned {
self.map(|inner| inner.into_cloneable_owned())
}
fn dry_resolve(&mut self) {}
async fn resolve(self) -> Self::AsyncOutput {
self
}
}