1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use futures::channel::oneshot;
use silkenweb_task::spawn_local;

use super::{
    children_with_id, document_head, wet_insert_mounted, wet_unmount, Document, MountHydro,
    MountHydroHead,
};
use crate::{
    document::MountedInHead,
    dom::{self, private::DomElement, Hydro},
    hydration::HydrationStats,
    mount_point,
    node::element::{
        child_vec::{ChildVec, ParentShared},
        Const, GenericElement, Namespace,
    },
};

impl Document for Hydro {
    type MountInHeadOutput = MountHydroHead;
    type MountOutput = MountHydro;

    /// See [`hydrate`] for more details.
    ///
    /// [`hydrate`] just calls [`Hydro::mount`].
    ///
    /// [`hydrate`]: crate::hydration::hydrate
    fn mount(id: &str, element: impl Into<GenericElement<Self, Const>>) -> Self::MountOutput {
        #[cfg(debug_assertions)]
        crate::log_panics();
        let element = element.into();
        let id = id.to_string();

        let (send, receive) = oneshot::channel();
        spawn_local(async move {
            let mut stats = HydrationStats::default();

            let mount_point = mount_point(&id);
            let wet_element = element.hydrate(&mount_point, &mut stats);
            wet_insert_mounted(&id, wet_element);
            let _ = send.send(stats);
        });

        MountHydro(receive)
    }

    fn mount_in_head(id: &str, head: super::DocumentHead<Self>) -> Self::MountInHeadOutput {
        let hydro_head_elem = <Hydro as dom::private::Dom>::Element::new(&Namespace::Html, "head");
        let child_vec = ChildVec::<Hydro, ParentShared>::new(hydro_head_elem.clone(), 0);

        MOUNTED_IN_HEAD.with(|m| m.mount(id, child_vec.run(children_with_id(head, id))));
        let id = id.to_string();
        let head_elem = document_head();

        let (send, receive) = oneshot::channel();
        spawn_local(async move {
            let mut stats = HydrationStats::default();
            hydro_head_elem.hydrate_in_head(head_elem, &id, &mut stats);
            let _ = send.send(stats);
        });

        MountHydroHead(receive)
    }

    fn unmount_all() {
        wet_unmount();
        MOUNTED_IN_HEAD.with(|m| m.unmount_all());
    }

    fn head_inner_html() -> String {
        MOUNTED_IN_HEAD.with(|m| m.inner_html())
    }
}

thread_local! {
    static MOUNTED_IN_HEAD: MountedInHead<Hydro> = MountedInHead::new();
}