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
use js_sys::JsString;
use std::borrow::Cow;
use std::rc::Rc;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
use web_sys::{Request, RequestInit, RequestMode, Response};
use yew::{create_portal, function_component, html, Properties, Reducible};
#[doc(hidden)]
pub use wasm_bindgen_futures;
#[doc(hidden)]
pub async fn fetch_script(url: Cow<'static, str>) -> String {
let mut opts = RequestInit::new();
opts.method("GET");
opts.mode(RequestMode::Cors);
let request = Request::new_with_str_and_init(&url, &opts).unwrap();
let window = web_sys::window().unwrap();
let resp_value = JsFuture::from(window.fetch_with_request(&request))
.await
.unwrap();
assert!(resp_value.is_instance_of::<Response>());
let resp: Response = resp_value.dyn_into().unwrap();
let text: JsString = JsFuture::from(resp.text().unwrap())
.await
.unwrap()
.unchecked_into();
text.into()
}
#[doc(hidden)]
pub enum ScriptLoader {
NotRequested,
Started,
Completed(Script),
}
impl Default for ScriptLoader {
fn default() -> Self {
Self::NotRequested
}
}
#[doc(hidden)]
pub enum ScriptLoaderAction {
Start,
Finish(Rc<String>),
}
impl Reducible for ScriptLoader {
type Action = ScriptLoaderAction;
fn reduce(self: Rc<Self>, action: Self::Action) -> Rc<Self> {
match action {
ScriptLoaderAction::Start => match *self {
ScriptLoader::NotRequested => Rc::new(Self::Started),
ScriptLoader::Started => unreachable!(
"script already started to load, can't receive another start request"
),
ScriptLoader::Completed(_) => unreachable!(
"script load already completed, can't receive another start request"
),
},
ScriptLoaderAction::Finish(content) => match *self {
ScriptLoader::NotRequested => {
unreachable!("script finished load, request should have started")
}
ScriptLoader::Started => Rc::new(Self::Completed(Script { content })),
ScriptLoader::Completed(_) => {
unreachable!("script completed load, can't receive another complete request")
}
},
}
}
}
#[derive(Clone, PartialEq)]
pub struct Script {
content: Rc<String>,
}
#[cfg_attr(documenting, doc(cfg(feature = "script")))]
#[derive(Properties, PartialEq)]
pub struct ScriptEffectProps {
pub script: Script,
}
#[cfg_attr(documenting, doc(cfg(feature = "script")))]
#[function_component(ScriptEffect)]
pub fn script_effect(props: &ScriptEffectProps) -> Html {
create_portal(
html! {
<script type="text/javascript">
{props.script.content.clone()}
</script>
},
web_sys::window()
.unwrap()
.document()
.unwrap()
.head()
.unwrap()
.into(),
)
}