yew_stdweb/app.rs
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
//! This module contains the `App` struct, which is used to bootstrap
//! a component in an isolated scope.
use crate::html::{Component, ComponentLink, NodeRef, Scope};
use crate::utils::document;
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(feature = "std_web")] {
use stdweb::web::{Element, INode, IParentNode};
} else if #[cfg(feature = "web_sys")] {
use web_sys::Element;
}
}
/// An instance of an application.
#[derive(Debug)]
pub struct App<COMP: Component> {
/// `Scope` holder
scope: Scope<COMP>,
}
impl<COMP> Default for App<COMP>
where
COMP: Component,
{
fn default() -> Self {
App::new()
}
}
impl<COMP> App<COMP>
where
COMP: Component,
COMP::Properties: Default,
{
/// The main entry point of a Yew program. It works similarly to the `program`
/// function in Elm. You should provide an initial model, `update` function
/// which will update the state of the model and a `view` function which
/// will render the model to a virtual DOM tree. If you would like to pass props,
/// use the `mount_with_props` method.
pub fn mount(self, element: Element) -> ComponentLink<COMP> {
clear_element(&element);
self.scope.mount_in_place(
element,
NodeRef::default(),
NodeRef::default(),
COMP::Properties::default(),
)
}
/// Alias to `mount("body", ...)`.
pub fn mount_to_body(self) -> ComponentLink<COMP> {
// Bootstrap the component for `Window` environment only (not for `Worker`)
let element = document()
.query_selector("body")
.expect("can't get body node for rendering")
.expect("can't unwrap body node");
self.mount(element)
}
/// Alternative to `mount` which replaces the body element with a component which has a body
/// element at the root of the HTML generated by its `view` method. Use this method when you
/// need to manipulate the body element. For example, adding/removing app-wide
/// CSS classes of the body element.
pub fn mount_as_body(self) -> ComponentLink<COMP> {
let html_element = document()
.query_selector("html")
.expect("can't get html node for rendering")
.expect("can't unwrap html node");
let body_element = document()
.query_selector("body")
.expect("can't get body node for rendering")
.expect("can't unwrap body node");
html_element
.remove_child(&body_element)
.expect("can't remove body child");
self.scope.mount_in_place(
html_element,
NodeRef::default(),
NodeRef::default(),
COMP::Properties::default(),
)
}
}
impl<COMP> App<COMP>
where
COMP: Component,
{
/// Creates a new `App` with a component in a context.
pub fn new() -> Self {
let scope = Scope::new(None);
App { scope }
}
/// The main entry point of a Yew program which also allows passing properties. It works
/// similarly to the `program` function in Elm. You should provide an initial model, `update`
/// function which will update the state of the model and a `view` function which
/// will render the model to a virtual DOM tree.
pub fn mount_with_props(
self,
element: Element,
props: COMP::Properties,
) -> ComponentLink<COMP> {
clear_element(&element);
self.scope
.mount_in_place(element, NodeRef::default(), NodeRef::default(), props)
}
/// Alias to `mount_with_props("body", ...)`.
pub fn mount_to_body_with_props(self, props: COMP::Properties) -> ComponentLink<COMP> {
// Bootstrap the component for `Window` environment only (not for `Worker`)
let element = document()
.query_selector("body")
.expect("can't get body node for rendering")
.expect("can't unwrap body node");
self.mount_with_props(element, props)
}
/// Alternative to `mount_with_props` which replaces the body element with a component which
/// has a body element at the root of the HTML generated by its `view` method. Use this method
/// when you need to manipulate the body element. For example, adding/removing app-wide
/// CSS classes of the body element.
pub fn mount_as_body_with_props(self, props: COMP::Properties) -> ComponentLink<COMP> {
let html_element = document()
.query_selector("html")
.expect("can't get html node for rendering")
.expect("can't unwrap html node");
let body_element = document()
.query_selector("body")
.expect("can't get body node for rendering")
.expect("can't unwrap body node");
html_element
.remove_child(&body_element)
.expect("can't remove body child");
self.scope
.mount_in_place(html_element, NodeRef::default(), NodeRef::default(), props)
}
}
/// Removes anything from the given element.
fn clear_element(element: &Element) {
while let Some(child) = element.last_child() {
element.remove_child(&child).expect("can't remove a child");
}
}