2020-01-08 03:52:00 -05:00
|
|
|
use std::rc::Rc;
|
|
|
|
use std::cell::RefCell;
|
2019-04-28 20:30:55 -04:00
|
|
|
use std::future::Future;
|
2019-06-11 09:29:46 -04:00
|
|
|
use std::iter::IntoIterator;
|
|
|
|
|
2018-02-25 06:58:20 -05:00
|
|
|
use discard::{Discard, DiscardOnDrop};
|
2018-10-22 20:16:54 -04:00
|
|
|
use futures_util::future::ready;
|
2018-04-25 19:01:52 -04:00
|
|
|
use futures_signals::{cancelable_future, CancelableFutureHandle};
|
|
|
|
use futures_signals::signal::{Signal, SignalExt};
|
2018-10-22 20:16:54 -04:00
|
|
|
use futures_signals::signal_vec::{VecDiff, SignalVec, SignalVecExt};
|
2019-06-11 09:29:46 -04:00
|
|
|
use web_sys::Node;
|
2019-06-20 19:57:47 -04:00
|
|
|
use wasm_bindgen::UnwrapThrowExt;
|
2019-06-11 09:29:46 -04:00
|
|
|
use wasm_bindgen_futures::futures_0_3::spawn_local;
|
|
|
|
|
2019-06-20 19:57:47 -04:00
|
|
|
use crate::bindings;
|
2019-06-11 09:29:46 -04:00
|
|
|
use crate::dom::Dom;
|
|
|
|
use crate::callbacks::Callbacks;
|
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-10-22 20:16:54 -04:00
|
|
|
where F: Future<Output = ()> + 'static {
|
2018-02-25 06:58:20 -05:00
|
|
|
// TODO make this more efficient ?
|
2018-10-22 20:16:54 -04:00
|
|
|
let (handle, future) = cancelable_future(future, || ());
|
2018-02-25 06:58:20 -05:00
|
|
|
|
2018-10-22 20:16:54 -04:00
|
|
|
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);
|
2018-10-22 20:16:54 -04:00
|
|
|
ready(())
|
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);
|
2018-10-22 20:16:54 -04:00
|
|
|
ready(())
|
2018-03-16 02:50:21 -04:00
|
|
|
})))
|
2018-03-01 08:39:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-25 06:58:20 -05:00
|
|
|
#[inline]
|
2019-06-20 19:57:47 -04:00
|
|
|
pub(crate) fn insert_children_iter<'a, A: IntoIterator<Item = &'a mut Dom>>(element: &Node, callbacks: &mut Callbacks, value: A) {
|
2018-02-25 06:58:20 -05:00
|
|
|
for dom in value.into_iter() {
|
2019-06-15 18:49:29 -04:00
|
|
|
// TODO can this be made more efficient ?
|
2018-02-25 06:58:20 -05:00
|
|
|
callbacks.after_insert.append(&mut dom.callbacks.after_insert);
|
|
|
|
callbacks.after_remove.append(&mut dom.callbacks.after_remove);
|
|
|
|
|
2019-06-20 19:57:47 -04:00
|
|
|
bindings::append_child(element, &dom.element);
|
2018-03-15 06:54:18 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-08 03:52:00 -05:00
|
|
|
fn after_insert(is_inserted: bool, callbacks: &mut Callbacks) {
|
|
|
|
callbacks.leak();
|
|
|
|
|
|
|
|
if is_inserted {
|
|
|
|
callbacks.trigger_after_insert();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub(crate) fn insert_child_signal<A>(element: Node, callbacks: &mut Callbacks, signal: A)
|
|
|
|
where A: Signal<Item = Option<Dom>> + 'static {
|
|
|
|
|
|
|
|
struct State {
|
|
|
|
is_inserted: bool,
|
|
|
|
child: Option<Dom>,
|
|
|
|
}
|
|
|
|
|
|
|
|
let state = Rc::new(RefCell::new(State {
|
|
|
|
is_inserted: false,
|
|
|
|
child: None,
|
|
|
|
}));
|
|
|
|
|
|
|
|
{
|
|
|
|
let state = state.clone();
|
|
|
|
|
|
|
|
callbacks.after_insert(move |_| {
|
|
|
|
let mut state = state.borrow_mut();
|
|
|
|
|
|
|
|
if !state.is_inserted {
|
|
|
|
state.is_inserted = true;
|
|
|
|
|
|
|
|
if let Some(ref mut child) = state.child {
|
|
|
|
child.callbacks.trigger_after_insert();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO verify that this will drop `child`
|
|
|
|
callbacks.after_remove(for_each(signal, move |mut child| {
|
|
|
|
let mut state = state.borrow_mut();
|
|
|
|
|
|
|
|
if let Some(old_child) = state.child.take() {
|
|
|
|
bindings::remove_child(&element, &old_child.element);
|
|
|
|
|
|
|
|
old_child.callbacks.discard();
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(ref mut new_child) = child {
|
|
|
|
bindings::append_child(&element, &new_child.element);
|
|
|
|
|
|
|
|
after_insert(state.is_inserted, &mut new_child.callbacks);
|
|
|
|
}
|
|
|
|
|
|
|
|
state.child = child;
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-11 09:29:46 -04:00
|
|
|
pub(crate) fn insert_children_signal_vec<A>(element: Node, callbacks: &mut Callbacks, signal: A)
|
|
|
|
where A: SignalVec<Item = Dom> + 'static {
|
2018-03-01 08:39:58 -05:00
|
|
|
|
|
|
|
struct State {
|
2018-04-25 19:01:52 -04:00
|
|
|
is_inserted: bool,
|
|
|
|
children: Vec<Dom>,
|
2018-03-01 08:39:58 -05:00
|
|
|
}
|
|
|
|
|
2020-01-08 03:52:00 -05:00
|
|
|
let state = Rc::new(RefCell::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 |_| {
|
2020-01-08 03:52:00 -05:00
|
|
|
let mut state = state.borrow_mut();
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-06-23 11:25:41 -04:00
|
|
|
fn clear(state: &mut State, element: &Node) {
|
|
|
|
// TODO is this correct ?
|
|
|
|
if state.children.len() > 0 {
|
|
|
|
bindings::remove_all_children(element);
|
|
|
|
|
|
|
|
for dom in state.children.drain(..) {
|
|
|
|
dom.callbacks.discard();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn insert_at(state: &mut State, element: &Node, new_index: usize, child: &Node) {
|
|
|
|
if let Some(dom) = state.children.get(new_index) {
|
|
|
|
bindings::insert_child_before(element, child, &dom.element);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
bindings::append_child(element, child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-20 19:57:47 -04:00
|
|
|
fn process_change(state: &mut State, element: &Node, change: VecDiff<Dom>) {
|
2018-03-01 08:39:58 -05:00
|
|
|
match change {
|
2018-04-25 19:01:52 -04:00
|
|
|
VecDiff::Replace { values } => {
|
2019-06-23 11:25:41 -04:00
|
|
|
clear(state, element);
|
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
|
|
|
|
2019-06-15 19:00:54 -04:00
|
|
|
let is_inserted = state.is_inserted;
|
|
|
|
|
|
|
|
for dom in state.children.iter_mut() {
|
2019-06-20 19:57:47 -04:00
|
|
|
bindings::append_child(element, &dom.element);
|
2019-06-15 18:49:29 -04:00
|
|
|
|
2019-06-23 11:25:41 -04:00
|
|
|
after_insert(is_inserted, &mut dom.callbacks);
|
2018-03-01 08:39:58 -05:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
VecDiff::InsertAt { index, mut value } => {
|
2019-06-23 11:25:41 -04:00
|
|
|
insert_at(state, element, index, &value.element);
|
2018-03-15 06:54:18 -04:00
|
|
|
|
2019-06-23 11:25:41 -04:00
|
|
|
after_insert(state.is_inserted, &mut value.callbacks);
|
2018-03-01 08:39:58 -05:00
|
|
|
|
|
|
|
// 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 } => {
|
2019-06-20 19:57:47 -04:00
|
|
|
bindings::append_child(element, &value.element);
|
2018-03-15 06:54:18 -04:00
|
|
|
|
2019-06-23 11:25:41 -04:00
|
|
|
after_insert(state.is_inserted, &mut value.callbacks);
|
2018-03-01 08:39:58 -05:00
|
|
|
|
|
|
|
// 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 } => {
|
2019-06-23 11:25:41 -04:00
|
|
|
let dom = &mut state.children[index];
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2019-06-23 11:25:41 -04:00
|
|
|
bindings::replace_child(element, &value.element, &dom.element);
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2019-06-23 11:25:41 -04:00
|
|
|
after_insert(state.is_inserted, &mut value.callbacks);
|
2018-03-01 08:39:58 -05:00
|
|
|
|
|
|
|
// TODO figure out a way to move this to the top
|
2018-03-15 06:54:18 -04:00
|
|
|
// TODO test this
|
2019-06-23 11:25:41 -04:00
|
|
|
::std::mem::swap(dom, &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);
|
|
|
|
|
2019-06-23 11:25:41 -04:00
|
|
|
insert_at(state, element, new_index, &value.element);
|
2019-06-20 19:57:47 -04:00
|
|
|
|
|
|
|
state.children.insert(new_index, value);
|
2018-04-25 19:01:52 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
VecDiff::RemoveAt { index } => {
|
2019-06-23 11:25:41 -04:00
|
|
|
let dom = state.children.remove(index);
|
2018-03-15 06:54:18 -04:00
|
|
|
|
2019-06-23 11:25:41 -04:00
|
|
|
bindings::remove_child(element, &dom.element);
|
|
|
|
|
|
|
|
dom.callbacks.discard();
|
2018-03-01 08:39:58 -05:00
|
|
|
},
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
VecDiff::Pop {} => {
|
2019-06-23 11:25:41 -04:00
|
|
|
let dom = state.children.pop().unwrap_throw();
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2019-06-23 11:25:41 -04:00
|
|
|
bindings::remove_child(element, &dom.element);
|
2018-03-01 08:39:58 -05:00
|
|
|
|
2019-06-23 11:25:41 -04:00
|
|
|
dom.callbacks.discard();
|
2018-03-01 08:39:58 -05:00
|
|
|
},
|
|
|
|
|
2018-04-25 19:01:52 -04:00
|
|
|
VecDiff::Clear {} => {
|
2019-06-23 11:25:41 -04:00
|
|
|
clear(state, element);
|
2018-03-01 08:39:58 -05:00
|
|
|
},
|
|
|
|
}
|
2019-06-20 11:52:52 -04:00
|
|
|
}
|
|
|
|
|
2019-06-23 11:25:41 -04:00
|
|
|
// TODO maybe move this into the after_insert callback and remove State
|
2019-06-20 11:52:52 -04:00
|
|
|
// TODO verify that this will drop `children`
|
|
|
|
callbacks.after_remove(for_each_vec(signal, move |change| {
|
2020-01-08 03:52:00 -05:00
|
|
|
let mut state = state.borrow_mut();
|
2019-06-20 11:52:52 -04:00
|
|
|
|
2019-06-20 19:57:47 -04:00
|
|
|
process_change(&mut state, &element, change);
|
2018-04-25 19:01:52 -04:00
|
|
|
}));
|
2018-03-01 08:39:58 -05:00
|
|
|
}
|