Adding in is_dom_loaded function

This commit is contained in:
Pauan 2018-07-04 01:34:13 -10:00
parent ffdc651b08
commit c422c61758
3 changed files with 95 additions and 10 deletions

View File

@ -15,6 +15,7 @@ stdweb-derive = "0.4.0"
lazy_static = "1.0.0"
discard = "1.0.3"
futures-core = "0.2.0"
futures-channel = "0.2.1"
#futures-signals = { path = "../rust-signals" }
futures-signals = { git = "https://github.com/Pauan/rust-signals" }
@ -29,6 +30,3 @@ debug-assertions = true
[profile.bench]
debug-assertions = true
[features]
debug-mode = []

View File

@ -1,5 +1,5 @@
use std::ops::Deref;
use stdweb::{Reference, Value, JsSerialize};
use stdweb::{Reference, Value, JsSerialize, Once};
use stdweb::unstable::{TryFrom, TryInto};
use stdweb::web::{IEventTarget, INode, IElement, IHtmlElement, HtmlElement, Node, window, TextNode, EventTarget, Element};
use stdweb::web::event::ConcreteEvent;
@ -9,10 +9,12 @@ use operations;
use operations::for_each;
use dom_operations;
use operations::{ValueDiscard, FnDiscard, spawn_future};
use futures_signals::signal::IntoSignal;
use futures_signals::signal::{IntoSignal, Signal};
use futures_signals::signal_vec::IntoSignalVec;
use futures_core::Never;
use futures_core::{Never, Async};
use futures_core::task::Context;
use futures_core::future::Future;
use futures_channel::oneshot;
use discard::{Discard, DiscardOnDrop};
@ -97,6 +99,94 @@ pub fn append_dom<A: INode>(parent: &A, mut dom: Dom) -> DomHandle {
}
struct IsDomLoadedEvent {
callback: Value,
}
impl IsDomLoadedEvent {
#[inline]
fn new<F>(callback: F) -> Self where F: FnOnce() + 'static {
// TODO use a proper type for the event
let callback = move |_: Value| {
callback();
};
Self {
callback: js!(
var callback = @{Once(callback)};
document.addEventListener("DOMContentLoaded", callback, true);
return callback;
),
}
}
}
impl Drop for IsDomLoadedEvent {
fn drop(&mut self) {
js! { @(no_return)
var callback = @{&self.callback};
document.removeEventListener("DOMContentLoaded", callback, true);
callback.drop();
}
}
}
enum IsDomLoaded {
Initial {},
Pending {
receiver: oneshot::Receiver<()>,
event: IsDomLoadedEvent,
},
Done {},
}
impl Signal for IsDomLoaded {
type Item = bool;
fn poll_change(&mut self, cx: &mut Context) -> Async<Option<Self::Item>> {
let result = match self {
IsDomLoaded::Initial {} => {
let is_ready: bool = js!( return document.readyState !== "loading"; ).try_into().unwrap();
if is_ready {
Async::Ready(Some(true))
} else {
let (sender, receiver) = oneshot::channel();
*self = IsDomLoaded::Pending {
receiver,
event: IsDomLoadedEvent::new(move || {
// TODO test this
sender.send(()).unwrap();
}),
};
Async::Ready(Some(false))
}
},
IsDomLoaded::Pending { receiver, .. } => {
receiver.poll(cx).unwrap().map(|_| Some(true))
},
IsDomLoaded::Done {} => {
Async::Ready(None)
},
};
if let Async::Ready(Some(true)) = result {
*self = IsDomLoaded::Done {};
}
result
}
}
#[inline]
pub fn is_dom_loaded() -> impl Signal<Item = bool> {
IsDomLoaded::Initial {}
}
#[inline]
pub fn text(value: &str) -> Dom {
Dom::new(js!( return document.createTextNode(@{value}); ).try_into().unwrap())
@ -516,10 +606,6 @@ impl<A: IElement + Clone + 'static> DomBuilder<A> {
self.callbacks.after_insert(move |callbacks| {
callbacks.after_remove(for_each(signal, move |value| {
if let Some(value) = value {
if cfg!(feature = "debug-mode") {
console!(log, element.as_ref(), js!( return @{element.as_ref()}.parentNode; ), js!( return document.body.contains(@{element.as_ref()}); ), js!( return @{element.as_ref()}.clientHeight; ), js!( return [].slice.call(@{element.as_ref()}.childNodes).map(function (x) { return x.clientHeight; }) ));
}
f(&element, value);
}
}));

View File

@ -12,6 +12,7 @@ extern crate lazy_static;
extern crate discard;
extern crate futures_core;
extern crate futures_channel;
extern crate futures_signals;