use super::{Arm, Component, Element, KeyedFor, Node, NonKeyedFor, SubApp, Text, WebSysNode};
use crate::app::{Application, WeakMain};
pub struct NodeList {
pub(super) nodes: Vec<Node>,
}
#[allow(clippy::new_without_default)]
impl NodeList {
pub fn new() -> Self {
Self { nodes: Vec::new() }
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
nodes: Vec::with_capacity(capacity),
}
}
pub fn new_capacity(&mut self, capacity: usize) {
if capacity > self.nodes.capacity() {
let additional = capacity - self.nodes.len();
self.nodes.reserve(additional);
}
}
pub fn is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn len(&self) -> usize {
self.nodes.len()
}
pub fn nodes_mut(&mut self) -> &mut Vec<Node> {
&mut self.nodes
}
pub fn no_update_comment(
&mut self,
text: &str,
real_parent: &web_sys::Node,
next_sibling: Option<&web_sys::Node>,
) {
self.nodes.push(Node::NeverChange(WebSysNode::new_comment(
text,
real_parent,
next_sibling,
)));
}
pub fn no_update_literal_string(
&mut self,
text: &str,
real_parent: &web_sys::Node,
next_sibling: Option<&web_sys::Node>,
) {
self.nodes.push(Node::NeverChange(WebSysNode::new_text(
text,
real_parent,
next_sibling,
)));
}
pub fn no_update_text(
&mut self,
text: &impl ToString,
real_parent: &web_sys::Node,
next_sibling: Option<&web_sys::Node>,
) {
self.nodes.push(Node::NeverChange(WebSysNode::new_text(
&text.to_string(),
real_parent,
next_sibling,
)));
}
pub fn text(&mut self, index: usize, value: &impl ToString) -> Option<&Text> {
if index >= self.nodes.len() {
debug_assert_eq!(index, self.nodes.len());
self.nodes
.push(Node::TextExpression(Text::new(value.to_string())));
match self.nodes.get_mut(index).expect("Last node added") {
Node::TextExpression(text) => Some(text),
_ => panic!("Expect a Node::TextExpression"),
}
} else {
match unsafe { self.nodes.get_unchecked_mut(index) } {
Node::TextExpression(text) => {
text.update_text(value.to_string());
None
}
_ => panic!("Expect a Node::TextExpression"),
}
}
}
pub fn element(&mut self, index: usize, tag: &str) -> (&mut Element, bool) {
let new = if index >= self.nodes.len() {
self.nodes.push(Node::Element(Element::new(tag)));
true
} else {
false
};
match self.nodes.get_mut(index).expect("Node at given index") {
Node::Element(e) => (e, new),
_ => panic!("Expect a Node::Element at the given index"),
}
}
pub fn non_keyed_for(&mut self, index: usize, capacity: usize) -> &mut NonKeyedFor {
if index >= self.nodes.len() {
self.nodes.push(Node::NonKeyedFor(NonKeyedFor::with_capacity(capacity)));
}
match self.nodes.get_mut(index).expect("Node at given index") {
Node::NonKeyedFor(f) => {
f
}
_ => panic!("Expect a Node::NonKeyedFor at the given index"),
}
}
pub fn keyed_for(&mut self, index: usize) -> &mut KeyedFor {
if index >= self.nodes.len() {
self.nodes.push(Node::KeyedFor(KeyedFor::new()));
}
match self.nodes.get_mut(index).expect("Node at given index") {
Node::KeyedFor(f) => f,
_ => panic!("Expect a Node::KeyedFor at the given index"),
}
}
pub fn arm(&mut self, index: usize) -> &mut Arm {
if index >= self.nodes.len() {
self.nodes.push(Node::Arm(Arm::new()));
}
match self.nodes.get_mut(index).expect("Not at given index") {
Node::Arm(a) => a,
_ => panic!("Expect a Node::Arm at the given index"),
}
}
pub fn component(&mut self, index: usize) -> (bool, &mut Component) {
let new = if index >= self.nodes.len() {
self.nodes.push(Node::Component(Component::new()));
true
} else {
false
};
match self.nodes.get_mut(index).expect("Node at given index") {
Node::Component(a) => (new, a),
_ => panic!("Expect a Node::Component at the given index"),
}
}
pub fn sub_app<A, B>(
&mut self,
id: u8,
real_parent: &web_sys::Node,
parent_main: WeakMain<A>,
) -> &SubApp
where
A: Application,
B: Application<Parent = WeakMain<A>>,
{
if self.nodes.is_empty() {
self.nodes.push(Node::SubApp(SubApp::new::<A, B>(
id,
real_parent,
parent_main,
)));
}
match unsafe { self.nodes.get_unchecked(0) } {
Node::SubApp(sa) => sa,
_ => panic!("Expect a Node::SubApp"),
}
}
pub fn tab_sub_app<A, B>(
&mut self,
id: u8,
real_parent: &web_sys::Node,
parent_main: WeakMain<A>,
) -> &SubApp
where
A: Application,
B: Application<Parent = WeakMain<A>>,
{
if self.nodes.is_empty() {
self.nodes.push(Node::SubApp(SubApp::new::<A, B>(
id,
real_parent,
parent_main,
)));
} else {
let same = match unsafe { self.nodes.get_unchecked(0) } {
Node::SubApp(sa) => sa.is_same_app::<B>(id),
_ => panic!("Expect a Node::SubApp"),
};
if !same {
self.remove_real_node(real_parent);
self.nodes.push(Node::SubApp(SubApp::new::<A, B>(
id,
real_parent,
parent_main,
)));
}
}
match unsafe { self.nodes.get_unchecked(0) } {
Node::SubApp(sa) => sa,
_ => panic!("Expect a Node::SubApp"),
}
}
pub(crate) fn remove_and_get_next_sibling(
&mut self,
real_parent: &web_sys::Node,
) -> Option<web_sys::Node> {
if self.nodes.is_empty() {
return None;
}
let mut last = self.nodes.pop().expect("Simi bug: Arm must not be empty");
let next_sibling = last.remove_and_get_next_sibling(real_parent);
self.remove_real_node(real_parent);
next_sibling
}
pub(crate) fn remove_real_node(&mut self, real_parent: &web_sys::Node) {
while let Some(mut node) = self.nodes.pop() {
node.remove_real_node(real_parent);
}
}
pub fn truncate(&mut self, size_after_removal: usize, real_parent: &web_sys::Node) {
if size_after_removal == 0 {
real_parent.set_text_content(None);
self.nodes.truncate(0);
return;
}
while self.nodes.len() > size_after_removal {
let mut node = self.nodes.pop().expect("No more node to remove");
node.remove_real_node(real_parent);
}
}
pub fn get_next_sibling(&self) -> Option<web_sys::Node> {
self.nodes
.last()
.map(super::Node::get_next_sibling)
.unwrap_or_else(|| None)
}
pub fn get_first_real_node(&self) -> Option<&web_sys::Node> {
self.nodes
.first()
.map(super::Node::get_first_real_node)
.unwrap_or_else(|| None)
}
pub(super) fn clone(&self, real_parent: &web_sys::Node) -> Self {
let mut nodes = Vec::with_capacity(self.nodes.capacity());
for n in self.nodes.iter() {
nodes.push(n.clone(real_parent));
}
Self { nodes }
}
pub(super) fn start_clone(&self) -> Self {
let mut nodes = Vec::with_capacity(self.nodes.capacity());
for n in self.nodes.iter() {
nodes.push(n.start_clone());
}
Self { nodes }
}
}