use crate::prelude::*;
use beet_core::prelude::*;
use beet_dom::prelude::*;
pub fn apply_requires_dom_idx(
mut commands: Commands,
attributes: Query<(Entity, &Attributes)>,
dyn_attrs: Query<(), (With<AttributeOf>, Added<SignalEffect>)>,
dyn_text_nodes: Query<
Entity,
(With<TextNode>, With<SignalEffect>, Without<AttributeOf>),
>,
dyn_fragments: Query<Entity, (With<FragmentNode>, Added<SignalEffect>)>,
parents: Query<&ChildOf>,
elements: Query<Entity, With<ElementNode>>,
) -> Result {
for entity in dyn_fragments.iter() {
let parent = parents
.iter_ancestors(entity)
.find(|e| elements.contains(*e))
.ok_or_else(|| {
bevyhow!(
"FragmentNode with SignalEffect must have an ElementNode parent"
)
})?;
commands.entity(parent).insert(RequiresDomIdx);
}
for entity in dyn_text_nodes.iter() {
let parent = parents
.iter_ancestors(entity)
.find(|e| elements.contains(*e))
.ok_or_else(|| {
bevyhow!(
"TextNode with SignalEffect must have an ElementNode parent"
)
})?;
commands.entity(entity).insert(RequiresDomIdx);
commands.entity(parent).insert(RequiresDomIdx);
}
for (entity, _) in attributes
.iter()
.filter(|(_, attrs)| attrs.iter().any(|attr| dyn_attrs.contains(attr)))
{
commands.entity(entity).insert(RequiresDomIdx);
}
Ok(())
}
#[allow(dead_code)]
pub(super) fn apply_root_dom_idx(
mut commands: Commands,
html_constants: Res<HtmlConstants>,
roots: Populated<Entity, Added<HtmlDocument>>,
children: Query<&Children>,
requires_idx: Query<(), Added<RequiresDomIdx>>,
) {
let mut id = 0;
for root in roots.iter() {
for entity in children
.iter_descendants_depth_first(root)
.filter(|entity| requires_idx.contains(*entity))
{
commands
.entity(entity)
.remove::<RequiresDomIdx>()
.insert(DomIdx::new(id));
commands.spawn((
AttributeOf::new(entity),
AttributeKey::new(html_constants.dom_idx_key.clone()),
TextNode::new(id.to_string()),
));
id += 1;
}
}
}
#[allow(dead_code)]
pub(super) fn apply_client_island_dom_idx(
mut commands: Commands,
html_constants: Res<HtmlConstants>,
roots: Populated<
(Entity, &DomIdx),
(Added<DomIdx>, Without<ChildOf>, Without<AttributeOf>),
>,
children: Query<&Children>,
requires_idx: Query<(), Added<RequiresDomIdx>>,
) {
for (root, idx) in roots.iter() {
let mut id = idx.inner() + 1; for entity in children
.iter_descendants_depth_first(root)
.filter(|entity| requires_idx.contains(*entity))
{
commands
.entity(entity)
.remove::<RequiresDomIdx>()
.insert(DomIdx::new(id));
commands.spawn((
AttributeOf::new(entity),
AttributeKey::new(html_constants.dom_idx_key.clone()),
TextNode::new(id.to_string()),
));
id += 1;
}
}
}
#[cfg(test)]
mod test {
use crate::prelude::*;
use beet_core::prelude::*;
use beet_dom::prelude::*;
use bevy::ecs::system::RunSystemOnce;
#[test]
fn applies_ids() {
let mut app = App::new();
app.add_plugins(SignalsPlugin);
let world = app.world_mut();
world.init_resource::<HtmlConstants>();
let (get, _set) = signal(2);
let div = world
.spawn((HtmlDocument, rsx! {
<div onclick=|| {}>
"child 1" <span>"child with signal"{get}</span> "child 2"
</div>
}))
.get::<Children>()
.unwrap()[0];
world.run_system_once(super::apply_root_dom_idx).unwrap();
world.get::<DomIdx>(div).unwrap().xpect_eq(DomIdx(0));
}
}