use std::{cell::Cell, rc::Rc};
use wasm_bindgen::UnwrapThrowExt;
use crate::{
component::{Comp, Component},
dom::{AChildNode, ElementTag, GroupedNodes},
queue_render::{
base::QrListRender,
dom::{QrGroupRepresentative, QrNode, QrTextNode},
val::QueueRender,
},
render::{
base::{ElementUpdater, MatchIfUpdater, NodesUpdater},
ListElementCreation,
},
};
impl<'a, C: Component> NodesUpdater<'a, C> {
pub fn create_qr_text_node(&mut self) -> Option<QrTextNode> {
let tn = if self.new_node() {
let tn = QrTextNode::default();
tn.insert_before_a_sibling(self.parent(), self.next_sibling());
self.nodes_mut().add_qr_node(QrNode::Text(tn.clone()));
Some(tn)
} else {
let index = self.index();
let qr_node = self.nodes_mut().get_qr_node(index);
match qr_node {
QrNode::Text(_) => None,
QrNode::ClonedWsNode(wsn) => match wsn.take() {
Some(wsn) => {
let tn = QrTextNode::with_cloned_node(wsn);
*qr_node = QrNode::Text(tn.clone());
Some(tn)
}
None => None,
},
QrNode::List(_) | QrNode::Group(_) => {
panic!("spair internal error: Expect a ClonedWsNode or Text");
}
}
};
self.next_index();
tn
}
pub fn create_qr_list_render<E, I, R>(
&mut self,
full_list: bool,
mode: ListElementCreation,
tag: E,
fn_render: R,
) -> Option<QrListRender<C, E, I>>
where
E: ElementTag,
I: Clone,
R: 'static + Fn(I, ElementUpdater<C>),
{
let list = if self.new_node() {
let end_flag_node = if full_list {
None
} else {
let n: web_sys::Node = crate::utils::document()
.create_comment("Mark the end of a qr list")
.into();
n.insert_before_a_sibling(self.parent(), self.next_sibling());
Some(n)
};
let list = QrListRender::new(
tag,
self.comp(),
self.parent().clone(),
end_flag_node,
fn_render,
mode.use_template(),
);
self.nodes_mut()
.add_qr_node(QrNode::List(list.make_representative()));
Some(list)
} else {
let index = self.index();
let comp = self.comp();
let parent = self.parent().clone();
let qr_node = self.nodes_mut().get_qr_node(index);
match qr_node {
QrNode::List(_) => None,
QrNode::ClonedWsNode(wsn) => match wsn.take() {
Some(wsn) => {
let list = QrListRender::new(
tag,
comp,
parent,
Some(wsn),
fn_render,
mode.use_template(),
);
*qr_node = QrNode::List(list.make_representative());
Some(list)
}
None => None,
},
QrNode::Text(_) | QrNode::Group(_) => {
panic!("spair internal error: Expect a ClonedWsNode or List");
}
}
};
self.next_index();
list
}
pub fn create_qr_match_if<T, R>(&mut self, fn_render: R) -> Option<QrMatchIfUpdater<C, T>>
where
R: 'static + Fn(&T, MatchIfUpdater<C>),
{
let group = if self.new_node() {
let r = QrMatchIfUpdater {
comp: self.comp(),
parent: self.parent().clone(),
nodes: GroupedNodes::new(),
fn_render: Box::new(fn_render),
unmounted: Rc::new(Cell::new(false)),
};
r.nodes
.end_flag_node()
.insert_before_a_sibling(self.parent(), self.next_sibling());
self.nodes_mut()
.add_qr_node(QrNode::Group(r.make_representative()));
Some(r)
} else {
let index = self.index();
let comp = self.comp();
let parent = self.parent().clone();
let qr_node = self.nodes_mut().get_qr_node(index);
match qr_node {
QrNode::Group(_) => None,
QrNode::ClonedWsNode(wsn) => match wsn.take() {
Some(wsn) => {
let r = QrMatchIfUpdater {
comp,
parent,
nodes: GroupedNodes::with_flag(wsn),
fn_render: Box::new(fn_render),
unmounted: Rc::new(Cell::new(false)),
};
*qr_node = QrNode::Group(r.make_representative());
Some(r)
}
None => None,
},
QrNode::Text(_) | QrNode::List(_) => {
panic!("spair internal error: Expect a ClonedWsNode or Group");
}
}
};
self.next_index();
group
}
}
type FnMatchIfUpdater<C, T> = Box<dyn Fn(&T, MatchIfUpdater<C>)>;
pub struct QrMatchIfUpdater<C: Component, T> {
comp: Comp<C>,
parent: web_sys::Node,
nodes: GroupedNodes,
fn_render: FnMatchIfUpdater<C, T>,
unmounted: Rc<Cell<bool>>,
}
impl<C: Component, T> QrMatchIfUpdater<C, T> {
pub fn make_representative(&self) -> QrGroupRepresentative {
QrGroupRepresentative::new(self.nodes.end_flag_node().clone(), self.unmounted.clone())
}
}
impl<C: Component, T> QueueRender<T> for QrMatchIfUpdater<C, T> {
fn render(&mut self, t: &T) {
let rc_comp = self.comp.upgrade();
let comp = rc_comp
.try_borrow()
.expect_throw("QrListRender::render::rc_comp.try_borrow().");
let state = comp.state();
let mi = MatchIfUpdater::new(&self.comp, state, &self.parent, &mut self.nodes);
(self.fn_render)(t, mi);
}
fn unmounted(&self) -> bool {
self.unmounted.get()
}
}