It now supports multiple dynamic children, by using comment markers

This commit is contained in:
Pauan 2021-04-30 18:08:29 +02:00
parent 16f09dd375
commit 2839a51ba9
3 changed files with 28 additions and 26 deletions

View File

@ -124,6 +124,12 @@ pub(crate) fn create_comment(value: &str) -> Comment {
DOCUMENT.with(|d| d.create_comment(value))
}
#[inline]
pub(crate) fn create_empty_node() -> Node {
// TODO is there a better way of doing this ?
create_comment(intern("")).into()
}
// TODO check that the attribute *actually* was changed
pub(crate) fn set_attribute(elem: &Element, key: &str, value: &str) {
elem.set_attribute(key, value).unwrap_throw();

View File

@ -245,8 +245,7 @@ impl Dom {
#[inline]
pub fn empty() -> Self {
// TODO is there a better way of doing this ?
Self::new(bindings::create_comment(intern("")).into())
Self::new(bindings::create_empty_node())
}
#[deprecated(since = "0.5.15", note = "Store the data explicitly in a component struct instead")]
@ -386,8 +385,6 @@ fn set_property<A, B, C>(element: &A, name: &B, value: C) where A: AsRef<JsValue
pub struct DomBuilder<A> {
element: A,
callbacks: Callbacks,
// TODO verify this with static types instead ?
dynamic_children: bool,
}
impl<A> DomBuilder<A> where A: JsCast {
@ -416,7 +413,6 @@ impl<A> DomBuilder<A> {
Self {
element: value,
callbacks: Callbacks::new(),
dynamic_children: false,
}
}
@ -577,14 +573,8 @@ impl<A> DomBuilder<A> where A: AsRef<EventTarget> {
}
impl<A> DomBuilder<A> where A: AsRef<Node> {
#[inline]
fn check_children(&self) {
assert_eq!(self.dynamic_children, false);
}
#[inline]
pub fn child<B: BorrowMut<Dom>>(mut self, mut child: B) -> Self {
self.check_children();
operations::insert_children_one(self.element.as_ref(), &mut self.callbacks, child.borrow_mut());
self
}
@ -592,14 +582,12 @@ impl<A> DomBuilder<A> where A: AsRef<Node> {
// TODO figure out how to make this owned rather than &mut
#[inline]
pub fn children<B: BorrowMut<Dom>, C: IntoIterator<Item = B>>(mut self, children: C) -> Self {
self.check_children();
operations::insert_children_iter(self.element.as_ref(), &mut self.callbacks, children);
self
}
#[inline]
pub fn text(self, value: &str) -> Self {
self.check_children();
// TODO should this intern ?
bindings::append_child(self.element.as_ref(), &bindings::create_text_node(value));
self
@ -610,7 +598,6 @@ impl<A> DomBuilder<A> where A: AsRef<Node> {
where B: AsStr,
C: Signal<Item = B> + 'static {
self.check_children();
let element = make_text_signal(&mut self.callbacks, value);
bindings::append_child(self.element.as_ref(), &element);
self
@ -620,8 +607,6 @@ impl<A> DomBuilder<A> where A: AsRef<Node> {
pub fn children_signal_vec<B>(mut self, children: B) -> Self
where B: SignalVec<Item = Dom> + 'static {
self.check_children();
self.dynamic_children = true;
operations::insert_children_signal_vec(self.element.as_ref().clone(), &mut self.callbacks, children);
self
}
@ -630,8 +615,6 @@ impl<A> DomBuilder<A> where A: AsRef<Node> {
pub fn child_signal<B>(mut self, child: B) -> Self
where B: Signal<Item = Option<Dom>> + 'static {
self.check_children();
self.dynamic_children = true;
operations::insert_child_signal(self.element.as_ref().clone(), &mut self.callbacks, child);
self
}

View File

@ -111,7 +111,7 @@ pub(crate) fn insert_child_signal<A>(element: Node, callbacks: &mut Callbacks, s
}
// TODO verify that this will drop `child`
fn after_remove(&mut self, element: &Node, child: Option<Dom>) {
fn after_remove(&mut self, element: &Node, marker: &Node, child: Option<Dom>) {
if let Some(old_child) = self.child.take() {
bindings::remove_child(&element, &old_child.element);
@ -121,7 +121,7 @@ pub(crate) fn insert_child_signal<A>(element: Node, callbacks: &mut Callbacks, s
self.child = child;
if let Some(new_child) = &mut self.child {
bindings::append_child(&element, &new_child.element);
bindings::insert_child_before(element, &new_child.element, marker);
after_insert(self.is_inserted, &mut new_child.callbacks);
}
@ -147,6 +147,11 @@ pub(crate) fn insert_child_signal<A>(element: Node, callbacks: &mut Callbacks, s
}
}
// TODO replace with https://github.com/whatwg/dom/issues/736
let marker = bindings::create_empty_node();
bindings::append_child(&element, &marker);
let state = State::new();
State::after_insert(state.clone(), callbacks);
@ -155,7 +160,7 @@ pub(crate) fn insert_child_signal<A>(element: Node, callbacks: &mut Callbacks, s
state: state.clone(),
signal: for_each(signal, move |child| {
let mut state = state.borrow_mut();
state.after_remove(&element, child);
state.after_remove(&element, &marker, child);
}),
});
}
@ -167,14 +172,16 @@ pub(crate) fn insert_children_signal_vec<A>(element: Node, callbacks: &mut Callb
struct State {
element: Node,
marker: Node,
is_inserted: bool,
children: Vec<Dom>,
}
impl State {
fn new(element: Node) -> Rc<RefCell<Self>> {
fn new(element: Node, marker: Node) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(State {
element,
marker,
is_inserted: false,
children: vec![],
}))
@ -212,7 +219,7 @@ pub(crate) fn insert_children_signal_vec<A>(element: Node, callbacks: &mut Callb
bindings::insert_child_before(&self.element, child, &dom.element);
} else {
bindings::append_child(&self.element, child);
bindings::insert_child_before(&self.element, child, &self.marker);
}
}
@ -226,8 +233,9 @@ pub(crate) fn insert_children_signal_vec<A>(element: Node, callbacks: &mut Callb
let is_inserted = self.is_inserted;
// TODO use createDocumentFragment ?
for dom in self.children.iter_mut() {
bindings::append_child(&self.element, &dom.element);
bindings::insert_child_before(&self.element, &dom.element, &self.marker);
after_insert(is_inserted, &mut dom.callbacks);
}
@ -243,7 +251,7 @@ pub(crate) fn insert_children_signal_vec<A>(element: Node, callbacks: &mut Callb
},
VecDiff::Push { mut value } => {
bindings::append_child(&self.element, &value.element);
bindings::insert_child_before(&self.element, &value.element, &self.marker);
after_insert(self.is_inserted, &mut value.callbacks);
@ -309,7 +317,12 @@ pub(crate) fn insert_children_signal_vec<A>(element: Node, callbacks: &mut Callb
}
}
let state = State::new(element);
// TODO replace with https://github.com/whatwg/dom/issues/736
let marker = bindings::create_empty_node();
bindings::append_child(&element, &marker);
let state = State::new(element, marker);
State::after_insert(state.clone(), callbacks);