2018-06-11 16:54:47 -04:00
|
|
|
use std::sync::{Arc, Mutex};
|
2018-04-25 19:01:52 -04:00
|
|
|
use std::mem::ManuallyDrop;
|
2018-02-25 06:58:20 -05:00
|
|
|
use stdweb::PromiseFuture;
|
|
|
|
use discard::{Discard, DiscardOnDrop};
|
2018-04-25 19:01:52 -04:00
|
|
|
use futures_signals::{cancelable_future, CancelableFutureHandle};
|
|
|
|
use futures_signals::signal::{Signal, SignalExt};
|
|
|
|
use futures_signals::signal_vec::{VecDiff, SignalVec, SignalVecExt, IntoSignalVec};
|
2018-02-25 06:58:20 -05:00
|
|
|
use dom_operations;
|
2018-04-25 19:01:52 -04:00
|
|
|
use dom::Dom;
|
2018-02-25 06:58:20 -05:00
|
|
|
use callbacks::Callbacks;
|
|
|
|
use std::iter::IntoIterator;
|
2018-04-25 19:01:52 -04:00
|
|
|
use stdweb::traits::INode;
|
|
|
|
use futures_core::Never;
|
|
|
|
use futures_core::future::Future;
|
2018-02-25 06:58:20 -05:00
|
|
|
|
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
// TODO this should probably be in stdweb
|
2018-02-25 06:58:20 -05:00
|
|
|
#[inline]
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) fn spawn_future<F>(future: F) -> DiscardOnDrop<CancelableFutureHandle>
|
2018-04-25 19:01:52 -04:00
|
|
|
where F: Future<Item = (), Error = Never> + 'static {
|
2018-02-25 06:58:20 -05:00
|
|
|
// TODO make this more efficient ?
|
|
|
|
let (handle, future) = cancelable_future(future, |_| ());
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
PromiseFuture::spawn_local(future);
|
2018-02-25 06:58:20 -05:00
|
|
|
|
2018-03-16 02:50:21 -04:00
|
|
|
handle
|
2018-02-25 06:58:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
#[inline]
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) fn for_each<A, B>(signal: A, mut callback: B) -> CancelableFutureHandle
|
2018-03-15 06:54:18 -04:00
|
|
|
where A: Signal + 'static,
|
|
|
|
B: FnMut(A::Item) + 'static {
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2018-03-16 02:50:21 -04:00
|
|
|
DiscardOnDrop::leak(spawn_future(signal.for_each(move |value| {
|
2018-03-01 08:39:58 -05:00
|
|
|
callback(value);
|
|
|
|
Ok(())
|
2018-03-16 02:50:21 -04:00
|
|
|
})))
|
2018-03-15 06:54:18 -04:00
|
|
|
}
|
2018-03-01 08:39:58 -05:00
|
|
|
|
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
#[inline]
|
|
|
|
fn for_each_vec<A, B>(signal: A, mut callback: B) -> CancelableFutureHandle
|
|
|
|
where A: SignalVec + 'static,
|
2018-04-25 19:01:52 -04:00
|
|
|
B: FnMut(VecDiff<A::Item>) + 'static {
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2018-03-16 02:50:21 -04:00
|
|
|
DiscardOnDrop::leak(spawn_future(signal.for_each(move |value| {
|
2018-03-15 06:54:18 -04:00
|
|
|
callback(value);
|
|
|
|
Ok(())
|
2018-03-16 02:50:21 -04:00
|
|
|
})))
|
2018-03-01 08:39:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2018-02-25 06:58:20 -05:00
|
|
|
// TODO inline this ?
|
|
|
|
pub fn insert_children_signal<A, B, C>(element: &A, callbacks: &mut Callbacks, signal: C)
|
|
|
|
where A: INode + Clone + 'static,
|
|
|
|
B: IntoIterator<Item = Dom>,
|
|
|
|
C: Signal<Item = B> + 'static {
|
|
|
|
|
|
|
|
let element = element.clone();
|
|
|
|
|
|
|
|
let mut old_children: Vec<Dom> = vec![];
|
|
|
|
|
|
|
|
let handle = for_each(signal, move |value| {
|
|
|
|
dom_operations::remove_all_children(&element);
|
|
|
|
|
|
|
|
old_children = value.into_iter().map(|mut dom| {
|
|
|
|
element.append_child(&dom.element);
|
|
|
|
|
|
|
|
// TODO don't trigger this if the parent isn't inserted into the DOM
|
|
|
|
dom.callbacks.trigger_after_insert();
|
|
|
|
|
|
|
|
dom
|
|
|
|
}).collect();
|
|
|
|
});
|
|
|
|
|
|
|
|
// TODO verify that this will drop `old_children`
|
2018-03-15 06:54:18 -04:00
|
|
|
callbacks.after_remove(handle);
|
2018-03-01 08:39:58 -05:00
|
|
|
}*/
|
2018-02-25 06:58:20 -05:00
|
|
|
|
|
|
|
#[inline]
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) fn insert_children_iter<'a, A: INode, B: IntoIterator<Item = &'a mut Dom>>(element: &A, callbacks: &mut Callbacks, value: B) {
|
2018-02-25 06:58:20 -05:00
|
|
|
for dom in value.into_iter() {
|
|
|
|
callbacks.after_insert.append(&mut dom.callbacks.after_insert);
|
|
|
|
callbacks.after_remove.append(&mut dom.callbacks.after_remove);
|
|
|
|
|
|
|
|
element.append_child(&dom.element);
|
|
|
|
}
|
|
|
|
}
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
|
|
|
|
// TODO move this into the discard crate
|
|
|
|
// TODO verify that this is correct and doesn't leak memory or cause memory safety
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) struct ValueDiscard<A>(ManuallyDrop<A>);
|
2018-03-15 06:54:18 -04:00
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
impl<A> ValueDiscard<A> {
|
2018-03-15 06:54:18 -04:00
|
|
|
#[inline]
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) fn new(value: A) -> Self {
|
2018-04-25 19:01:52 -04:00
|
|
|
ValueDiscard(ManuallyDrop::new(value))
|
2018-03-15 06:54:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
impl<A> Discard for ValueDiscard<A> {
|
2018-03-15 06:54:18 -04:00
|
|
|
#[inline]
|
|
|
|
fn discard(self) {
|
2018-04-25 19:01:52 -04:00
|
|
|
// TODO verify that this works
|
|
|
|
ManuallyDrop::into_inner(self.0);
|
2018-03-15 06:54:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO move this into the discard crate
|
2018-04-25 19:01:52 -04:00
|
|
|
// TODO replace this with an impl for FnOnce() ?
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) struct FnDiscard<A>(A);
|
2018-03-15 06:54:18 -04:00
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
impl<A> FnDiscard<A> where A: FnOnce() {
|
2018-03-15 06:54:18 -04:00
|
|
|
#[inline]
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) fn new(f: A) -> Self {
|
2018-04-25 19:01:52 -04:00
|
|
|
FnDiscard(f)
|
2018-03-15 06:54:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
impl<A> Discard for FnDiscard<A> where A: FnOnce() {
|
2018-03-15 06:54:18 -04:00
|
|
|
#[inline]
|
|
|
|
fn discard(self) {
|
2018-04-25 19:01:52 -04:00
|
|
|
self.0();
|
2018-03-15 06:54:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-07-03 23:44:50 -04:00
|
|
|
pub(crate) fn insert_children_signal_vec<A, B>(element: &A, callbacks: &mut Callbacks, signal: B)
|
2018-03-01 08:39:58 -05:00
|
|
|
where A: INode + Clone + 'static,
|
2018-04-25 19:01:52 -04:00
|
|
|
B: IntoSignalVec<Item = Dom>,
|
|
|
|
B::SignalVec: 'static {
|
2018-03-01 08:39:58 -05:00
|
|
|
|
|
|
|
let element = element.clone();
|
|
|
|
|
|
|
|
// TODO does this create a new struct type every time ?
|
|
|
|
struct State {
|
2018-04-25 19:01:52 -04:00
|
|
|
is_inserted: bool,
|
|
|
|
children: Vec<Dom>,
|
2018-03-01 08:39:58 -05:00
|
|
|
}
|
|
|
|
|
2018-06-11 16:54:47 -04:00
|
|
|
// TODO use two separate Arcs ?
|
|
|
|
let state = Arc::new(Mutex::new(State {
|
2018-04-25 19:01:52 -04:00
|
|
|
is_inserted: false,
|
|
|
|
children: vec![],
|
|
|
|
}));
|
2018-03-01 08:39:58 -05:00
|
|
|
|
|
|
|
{
|
|
|
|
let state = state.clone();
|
|
|
|
|
|
|
|
callbacks.after_insert(move |_| {
|
2018-06-11 16:54:47 -04:00
|
|
|
let mut state = state.lock().unwrap();
|
2018-04-25 19:01:52 -04:00
|
|
|
|
|
|
|
if !state.is_inserted {
|
|
|
|
state.is_inserted = true;
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
for dom in state.children.iter_mut() {
|
2018-03-01 08:39:58 -05:00
|
|
|
dom.callbacks.trigger_after_insert();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
// TODO verify that this will drop `children`
|
|
|
|
callbacks.after_remove(for_each_vec(signal.into_signal_vec(), move |change| {
|
2018-06-11 16:54:47 -04:00
|
|
|
let mut state = state.lock().unwrap();
|
2018-04-25 19:01:52 -04:00
|
|
|
|
2018-03-01 08:39:58 -05:00
|
|
|
match change {
|
2018-04-25 19:01:52 -04:00
|
|
|
VecDiff::Replace { values } => {
|
2018-06-09 14:45:41 -04:00
|
|
|
// TODO is this correct ?
|
|
|
|
if state.children.len() > 0 {
|
|
|
|
dom_operations::remove_all_children(&element);
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2018-06-09 14:45:41 -04:00
|
|
|
for dom in state.children.drain(..) {
|
|
|
|
dom.callbacks.discard();
|
|
|
|
}
|
2018-03-15 06:54:18 -04:00
|
|
|
}
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
state.children = values;
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
let is_inserted = state.is_inserted;
|
2018-03-15 06:54:18 -04:00
|
|
|
|
2018-03-01 08:39:58 -05:00
|
|
|
// TODO use document fragment ?
|
2018-04-25 19:01:52 -04:00
|
|
|
for dom in state.children.iter_mut() {
|
2018-03-15 06:54:18 -04:00
|
|
|
dom.callbacks.leak();
|
|
|
|
|
2018-03-01 08:39:58 -05:00
|
|
|
element.append_child(&dom.element);
|
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
if is_inserted {
|
2018-03-01 08:39:58 -05:00
|
|
|
dom.callbacks.trigger_after_insert();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
VecDiff::InsertAt { index, mut value } => {
|
2018-03-01 08:39:58 -05:00
|
|
|
// TODO better usize -> u32 conversion
|
|
|
|
dom_operations::insert_at(&element, index as u32, &value.element);
|
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
value.callbacks.leak();
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
if state.is_inserted {
|
2018-03-01 08:39:58 -05:00
|
|
|
value.callbacks.trigger_after_insert();
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO figure out a way to move this to the top
|
2018-04-25 19:01:52 -04:00
|
|
|
state.children.insert(index, value);
|
2018-03-01 08:39:58 -05:00
|
|
|
},
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
VecDiff::Push { mut value } => {
|
2018-03-15 06:54:18 -04:00
|
|
|
element.append_child(&value.element);
|
|
|
|
|
|
|
|
value.callbacks.leak();
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
if state.is_inserted {
|
2018-03-01 08:39:58 -05:00
|
|
|
value.callbacks.trigger_after_insert();
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO figure out a way to move this to the top
|
2018-04-25 19:01:52 -04:00
|
|
|
state.children.push(value);
|
2018-03-01 08:39:58 -05:00
|
|
|
},
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
VecDiff::UpdateAt { index, mut value } => {
|
2018-03-01 08:39:58 -05:00
|
|
|
// TODO better usize -> u32 conversion
|
2018-03-15 06:54:18 -04:00
|
|
|
dom_operations::update_at(&element, index as u32, &value.element);
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
value.callbacks.leak();
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
if state.is_inserted {
|
2018-03-01 08:39:58 -05:00
|
|
|
value.callbacks.trigger_after_insert();
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO figure out a way to move this to the top
|
2018-03-15 06:54:18 -04:00
|
|
|
// TODO test this
|
2018-04-25 19:01:52 -04:00
|
|
|
::std::mem::swap(&mut state.children[index], &mut value);
|
2018-03-15 06:54:18 -04:00
|
|
|
|
|
|
|
value.callbacks.discard();
|
|
|
|
},
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
VecDiff::Move { old_index, new_index } => {
|
|
|
|
let value = state.children.remove(old_index);
|
|
|
|
|
|
|
|
state.children.insert(new_index, value);
|
|
|
|
|
|
|
|
// TODO better usize -> u32 conversion
|
|
|
|
dom_operations::move_from_to(&element, old_index as u32, new_index as u32);
|
|
|
|
},
|
|
|
|
|
|
|
|
VecDiff::RemoveAt { index } => {
|
2018-03-15 06:54:18 -04:00
|
|
|
// TODO better usize -> u32 conversion
|
|
|
|
dom_operations::remove_at(&element, index as u32);
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
state.children.remove(index).callbacks.discard();
|
2018-03-01 08:39:58 -05:00
|
|
|
},
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
VecDiff::Pop {} => {
|
|
|
|
let index = state.children.len() - 1;
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2018-03-15 06:54:18 -04:00
|
|
|
// TODO create remove_last_child function ?
|
2018-03-01 08:39:58 -05:00
|
|
|
// TODO better usize -> u32 conversion
|
|
|
|
dom_operations::remove_at(&element, index as u32);
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
state.children.pop().unwrap().callbacks.discard();
|
2018-03-01 08:39:58 -05:00
|
|
|
},
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
VecDiff::Clear {} => {
|
2018-06-09 14:45:41 -04:00
|
|
|
// TODO is this correct ?
|
|
|
|
// TODO is this needed, or is it guaranteed by VecDiff ?
|
|
|
|
if state.children.len() > 0 {
|
|
|
|
dom_operations::remove_all_children(&element);
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2018-06-09 14:45:41 -04:00
|
|
|
for dom in state.children.drain(..) {
|
|
|
|
dom.callbacks.discard();
|
|
|
|
}
|
2018-03-15 06:54:18 -04:00
|
|
|
}
|
2018-03-01 08:39:58 -05:00
|
|
|
},
|
|
|
|
}
|
2018-04-25 19:01:52 -04:00
|
|
|
}));
|
2018-03-01 08:39:58 -05:00
|
|
|
}
|