mirror of https://github.com/linebender/xilem
xilem_web: Fix `DomChildrenSplice::with_scratch` (#484)
I'm surprised that this was not noticed yet, `DomChildrenSplice::with_scratch` previously only appended new elements to the end of the children of an element in the DOM tree, whereas it should've inserted it at the current index of the `ElementSplice`. This should fix this, using a `DocumentFragment` which is shared on the `ViewCtx` to avoid unnecessary allocations.
This commit is contained in:
parent
0bca54ae52
commit
544a4a1ca9
|
@ -31,6 +31,7 @@ features = [
|
||||||
"console",
|
"console",
|
||||||
"CssStyleDeclaration",
|
"CssStyleDeclaration",
|
||||||
"Document",
|
"Document",
|
||||||
|
"DocumentFragment",
|
||||||
"DomTokenList",
|
"DomTokenList",
|
||||||
"Element",
|
"Element",
|
||||||
"Event",
|
"Event",
|
||||||
|
|
|
@ -25,10 +25,20 @@ impl MessageThunk {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The [`View`](`crate::core::View`) `Context` which is used for all [`DomView`](`crate::DomView`)s
|
/// The [`View`](`crate::core::View`) `Context` which is used for all [`DomView`](`crate::DomView`)s
|
||||||
#[derive(Default)]
|
|
||||||
pub struct ViewCtx {
|
pub struct ViewCtx {
|
||||||
id_path: Vec<ViewId>,
|
id_path: Vec<ViewId>,
|
||||||
app_ref: Option<Box<dyn AppRunner>>,
|
app_ref: Option<Box<dyn AppRunner>>,
|
||||||
|
pub(crate) fragment: Rc<web_sys::DocumentFragment>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for ViewCtx {
|
||||||
|
fn default() -> Self {
|
||||||
|
ViewCtx {
|
||||||
|
id_path: Vec::default(),
|
||||||
|
app_ref: None,
|
||||||
|
fragment: Rc::new(crate::document().create_document_fragment()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ViewCtx {
|
impl ViewCtx {
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
//! Basic builder functions to create DOM elements, such as [`html::div`]
|
//! Basic builder functions to create DOM elements, such as [`html::div`]
|
||||||
|
|
||||||
use std::any::Any;
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
use std::{any::Any, rc::Rc};
|
||||||
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -135,6 +135,7 @@ pub struct DomChildrenSplice<'a, 'b, 'c, 'd> {
|
||||||
children: VecSplice<'b, 'c, AnyPod>,
|
children: VecSplice<'b, 'c, AnyPod>,
|
||||||
ix: usize,
|
ix: usize,
|
||||||
parent: &'d web_sys::Node,
|
parent: &'d web_sys::Node,
|
||||||
|
fragment: Rc<web_sys::DocumentFragment>,
|
||||||
parent_was_removed: bool,
|
parent_was_removed: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,6 +145,7 @@ impl<'a, 'b, 'c, 'd> DomChildrenSplice<'a, 'b, 'c, 'd> {
|
||||||
children: &'b mut Vec<AnyPod>,
|
children: &'b mut Vec<AnyPod>,
|
||||||
vec_splice_scratch: &'c mut Vec<AnyPod>,
|
vec_splice_scratch: &'c mut Vec<AnyPod>,
|
||||||
parent: &'d web_sys::Node,
|
parent: &'d web_sys::Node,
|
||||||
|
fragment: Rc<web_sys::DocumentFragment>,
|
||||||
parent_was_deleted: bool,
|
parent_was_deleted: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -151,6 +153,7 @@ impl<'a, 'b, 'c, 'd> DomChildrenSplice<'a, 'b, 'c, 'd> {
|
||||||
children: VecSplice::new(children, vec_splice_scratch),
|
children: VecSplice::new(children, vec_splice_scratch),
|
||||||
ix: 0,
|
ix: 0,
|
||||||
parent,
|
parent,
|
||||||
|
fragment,
|
||||||
parent_was_removed: parent_was_deleted,
|
parent_was_removed: parent_was_deleted,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,12 +162,20 @@ impl<'a, 'b, 'c, 'd> DomChildrenSplice<'a, 'b, 'c, 'd> {
|
||||||
impl<'a, 'b, 'c, 'd> ElementSplice<AnyPod> for DomChildrenSplice<'a, 'b, 'c, 'd> {
|
impl<'a, 'b, 'c, 'd> ElementSplice<AnyPod> for DomChildrenSplice<'a, 'b, 'c, 'd> {
|
||||||
fn with_scratch<R>(&mut self, f: impl FnOnce(&mut AppendVec<AnyPod>) -> R) -> R {
|
fn with_scratch<R>(&mut self, f: impl FnOnce(&mut AppendVec<AnyPod>) -> R) -> R {
|
||||||
let ret = f(self.scratch);
|
let ret = f(self.scratch);
|
||||||
for element in self.scratch.drain() {
|
if !self.scratch.is_empty() {
|
||||||
|
for element in self.scratch.drain() {
|
||||||
|
self.fragment
|
||||||
|
.append_child(element.node.as_ref())
|
||||||
|
.unwrap_throw();
|
||||||
|
self.children.insert(element);
|
||||||
|
self.ix += 1;
|
||||||
|
}
|
||||||
self.parent
|
self.parent
|
||||||
.append_child(element.node.as_ref())
|
.insert_before(
|
||||||
|
self.fragment.as_ref(),
|
||||||
|
self.children.next_mut().map(|p| p.node.as_ref()),
|
||||||
|
)
|
||||||
.unwrap_throw();
|
.unwrap_throw();
|
||||||
self.children.insert(element);
|
|
||||||
self.ix += 1;
|
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
@ -262,6 +273,7 @@ where
|
||||||
&mut element.props.children,
|
&mut element.props.children,
|
||||||
&mut state.vec_splice_scratch,
|
&mut state.vec_splice_scratch,
|
||||||
element.node.as_ref(),
|
element.node.as_ref(),
|
||||||
|
ctx.fragment.clone(),
|
||||||
element.was_removed,
|
element.was_removed,
|
||||||
);
|
);
|
||||||
children.dyn_seq_rebuild(
|
children.dyn_seq_rebuild(
|
||||||
|
@ -290,6 +302,7 @@ pub(crate) fn teardown_element<State, Action, Element, SeqMarker>(
|
||||||
&mut element.props.children,
|
&mut element.props.children,
|
||||||
&mut state.vec_splice_scratch,
|
&mut state.vec_splice_scratch,
|
||||||
element.node.as_ref(),
|
element.node.as_ref(),
|
||||||
|
ctx.fragment.clone(),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
children.dyn_seq_teardown(&mut state.seq_state, ctx, &mut dom_children_splice);
|
children.dyn_seq_teardown(&mut state.seq_state, ctx, &mut dom_children_splice);
|
||||||
|
|
Loading…
Reference in New Issue