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",
|
||||
"CssStyleDeclaration",
|
||||
"Document",
|
||||
"DocumentFragment",
|
||||
"DomTokenList",
|
||||
"Element",
|
||||
"Event",
|
||||
|
|
|
@ -25,10 +25,20 @@ impl MessageThunk {
|
|||
}
|
||||
|
||||
/// The [`View`](`crate::core::View`) `Context` which is used for all [`DomView`](`crate::DomView`)s
|
||||
#[derive(Default)]
|
||||
pub struct ViewCtx {
|
||||
id_path: Vec<ViewId>,
|
||||
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 {
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
|
||||
//! Basic builder functions to create DOM elements, such as [`html::div`]
|
||||
|
||||
use std::any::Any;
|
||||
use std::borrow::Cow;
|
||||
use std::{any::Any, rc::Rc};
|
||||
use wasm_bindgen::{JsCast, UnwrapThrowExt};
|
||||
|
||||
use crate::{
|
||||
|
@ -135,6 +135,7 @@ pub struct DomChildrenSplice<'a, 'b, 'c, 'd> {
|
|||
children: VecSplice<'b, 'c, AnyPod>,
|
||||
ix: usize,
|
||||
parent: &'d web_sys::Node,
|
||||
fragment: Rc<web_sys::DocumentFragment>,
|
||||
parent_was_removed: bool,
|
||||
}
|
||||
|
||||
|
@ -144,6 +145,7 @@ impl<'a, 'b, 'c, 'd> DomChildrenSplice<'a, 'b, 'c, 'd> {
|
|||
children: &'b mut Vec<AnyPod>,
|
||||
vec_splice_scratch: &'c mut Vec<AnyPod>,
|
||||
parent: &'d web_sys::Node,
|
||||
fragment: Rc<web_sys::DocumentFragment>,
|
||||
parent_was_deleted: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -151,6 +153,7 @@ impl<'a, 'b, 'c, 'd> DomChildrenSplice<'a, 'b, 'c, 'd> {
|
|||
children: VecSplice::new(children, vec_splice_scratch),
|
||||
ix: 0,
|
||||
parent,
|
||||
fragment,
|
||||
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> {
|
||||
fn with_scratch<R>(&mut self, f: impl FnOnce(&mut AppendVec<AnyPod>) -> R) -> R {
|
||||
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
|
||||
.append_child(element.node.as_ref())
|
||||
.insert_before(
|
||||
self.fragment.as_ref(),
|
||||
self.children.next_mut().map(|p| p.node.as_ref()),
|
||||
)
|
||||
.unwrap_throw();
|
||||
self.children.insert(element);
|
||||
self.ix += 1;
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
@ -262,6 +273,7 @@ where
|
|||
&mut element.props.children,
|
||||
&mut state.vec_splice_scratch,
|
||||
element.node.as_ref(),
|
||||
ctx.fragment.clone(),
|
||||
element.was_removed,
|
||||
);
|
||||
children.dyn_seq_rebuild(
|
||||
|
@ -290,6 +302,7 @@ pub(crate) fn teardown_element<State, Action, Element, SeqMarker>(
|
|||
&mut element.props.children,
|
||||
&mut state.vec_splice_scratch,
|
||||
element.node.as_ref(),
|
||||
ctx.fragment.clone(),
|
||||
true,
|
||||
);
|
||||
children.dyn_seq_teardown(&mut state.seq_state, ctx, &mut dom_children_splice);
|
||||
|
|
Loading…
Reference in New Issue