Changing to use document fragments for dynamic child replacement

This commit is contained in:
Pauan 2019-06-16 00:49:29 +02:00
parent e5957b7831
commit e4b2347149
3 changed files with 34 additions and 23 deletions

View File

@ -38,6 +38,7 @@ features = [
"CssStyleRule",
"CssStyleSheet",
"Document",
"DocumentFragment",
"DomTokenList",
"Element",
"Event",

View File

@ -28,10 +28,10 @@ impl<A: Discard> IRemove for A {
}
pub(crate) struct InsertCallback(Box<IInsertCallback>);
pub(crate) struct InsertCallback(Box<dyn IInsertCallback>);
// TODO is there a more efficient way of doing this ?
pub(crate) struct RemoveCallback(Box<IRemove>);
pub(crate) struct RemoveCallback(Box<dyn IRemove>);
impl std::fmt::Debug for InsertCallback {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
@ -76,25 +76,27 @@ impl Callbacks {
// TODO runtime checks to make sure this isn't called multiple times ?
#[inline]
pub(crate) fn trigger_after_insert(&mut self) {
let mut callbacks = Callbacks::new();
if !self.after_insert.is_empty() {
let mut callbacks = Callbacks::new();
// TODO verify that this is correct
// TODO is this the most efficient way to accomplish this ?
std::mem::swap(&mut callbacks.after_remove, &mut self.after_remove);
// TODO verify that this is correct
// TODO is this the most efficient way to accomplish this ?
std::mem::swap(&mut callbacks.after_remove, &mut self.after_remove);
for f in self.after_insert.drain(..) {
f.0.call(&mut callbacks);
for f in self.after_insert.drain(..) {
f.0.call(&mut callbacks);
}
// TODO verify that this is correct
self.after_insert = vec![];
// TODO figure out a better way of verifying this
assert_eq!(callbacks.after_insert.len(), 0);
// TODO verify that this is correct
// TODO what if `callbacks` is leaked ?
std::mem::swap(&mut callbacks.after_remove, &mut self.after_remove);
}
// TODO verify that this is correct
self.after_insert = vec![];
// TODO figure out a better way of verifying this
assert_eq!(callbacks.after_insert.len(), 0);
// TODO verify that this is correct
// TODO what if `callbacks` is leaked ?
std::mem::swap(&mut callbacks.after_remove, &mut self.after_remove);
}
#[inline]

View File

@ -14,6 +14,7 @@ use wasm_bindgen_futures::futures_0_3::spawn_local;
use crate::dom_operations;
use crate::dom::Dom;
use crate::callbacks::Callbacks;
use crate::utils::document;
#[inline]
@ -83,6 +84,7 @@ pub fn insert_children_signal<A, B, C>(element: &A, callbacks: &mut Callbacks, s
#[inline]
pub(crate) fn insert_children_iter<'a, A: IntoIterator<Item = &'a mut Dom>>(element: &Node, callbacks: &mut Callbacks, value: A) {
for dom in value.into_iter() {
// TODO can this be made more efficient ?
callbacks.after_insert.append(&mut dom.callbacks.after_insert);
callbacks.after_remove.append(&mut dom.callbacks.after_remove);
@ -139,15 +141,21 @@ pub(crate) fn insert_children_signal_vec<A>(element: Node, callbacks: &mut Callb
state.children = values;
let is_inserted = state.is_inserted;
let fragment = document().create_document_fragment();
// TODO use document fragment ?
for dom in state.children.iter_mut() {
// TODO does this allocate if the filtered Vec is empty ?
let after_inserts = state.children.iter_mut().filter(|dom| {
dom.callbacks.leak();
element.append_child(&dom.element).unwrap_throw();
fragment.append_child(&dom.element).unwrap_throw();
if is_inserted {
!dom.callbacks.after_insert.is_empty()
}).collect::<Vec<_>>();
element.append_child(&fragment).unwrap_throw();
if state.is_inserted {
for dom in after_inserts {
dom.callbacks.trigger_after_insert();
}
}