mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-26 14:10:20 +00:00
allow many attributes to be attached to one element
This commit is contained in:
parent
dc446b5e5b
commit
fc8c25280a
12 changed files with 289 additions and 96 deletions
|
@ -1,5 +1,7 @@
|
||||||
use crate::any_props::AnyProps;
|
use crate::any_props::AnyProps;
|
||||||
use crate::innerlude::{BorrowedAttributeValue, VComponent, VPlaceholder, VText};
|
use crate::innerlude::{
|
||||||
|
AttributeType, BorrowedAttributeValue, MountedAttribute, VComponent, VPlaceholder, VText,
|
||||||
|
};
|
||||||
use crate::mutations::Mutation;
|
use crate::mutations::Mutation;
|
||||||
use crate::mutations::Mutation::*;
|
use crate::mutations::Mutation::*;
|
||||||
use crate::nodes::VNode;
|
use crate::nodes::VNode;
|
||||||
|
@ -283,7 +285,7 @@ impl<'b> VirtualDom {
|
||||||
let id = self.assign_static_node_as_dynamic(path, root, node, attr_id);
|
let id = self.assign_static_node_as_dynamic(path, root, node, attr_id);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
self.write_attribute(&node.dynamic_attrs[attr_id], id);
|
self.write_attribute_type(&node.dynamic_attrs[attr_id], id);
|
||||||
|
|
||||||
// Only push the dynamic attributes forward if they match the current path (same element)
|
// Only push the dynamic attributes forward if they match the current path (same element)
|
||||||
match attrs.next_if(|(_, p)| *p == path) {
|
match attrs.next_if(|(_, p)| *p == path) {
|
||||||
|
@ -294,10 +296,20 @@ impl<'b> VirtualDom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_attribute(&mut self, attribute: &'b crate::Attribute<'b>, id: ElementId) {
|
fn write_attribute_type(&mut self, attribute: &'b MountedAttribute<'b>, id: ElementId) {
|
||||||
// Make sure we set the attribute's associated id
|
// Make sure we set the attribute's associated id
|
||||||
attribute.mounted_element.set(id);
|
attribute.mounted_element.set(id);
|
||||||
|
match &attribute.ty {
|
||||||
|
AttributeType::Single(attribute) => self.write_attribute(attribute, id),
|
||||||
|
AttributeType::Many(attribute) => {
|
||||||
|
for attribute in *attribute {
|
||||||
|
self.write_attribute(attribute, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn write_attribute(&mut self, attribute: &'b crate::Attribute<'b>, id: ElementId) {
|
||||||
// Safety: we promise not to re-alias this text later on after committing it to the mutation
|
// Safety: we promise not to re-alias this text later on after committing it to the mutation
|
||||||
let unbounded_name: &str = unsafe { std::mem::transmute(attribute.name) };
|
let unbounded_name: &str = unsafe { std::mem::transmute(attribute.name) };
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
any_props::AnyProps,
|
any_props::AnyProps,
|
||||||
arena::ElementId,
|
arena::ElementId,
|
||||||
innerlude::{BorrowedAttributeValue, DirtyScope, VComponent, VPlaceholder, VText},
|
innerlude::{
|
||||||
|
AttributeType, BorrowedAttributeValue, DirtyScope, VComponent, VPlaceholder, VText,
|
||||||
|
},
|
||||||
mutations::Mutation,
|
mutations::Mutation,
|
||||||
nodes::RenderReturn,
|
nodes::RenderReturn,
|
||||||
nodes::{DynamicNode, VNode},
|
nodes::{DynamicNode, VNode},
|
||||||
|
@ -103,16 +105,51 @@ impl<'b> VirtualDom {
|
||||||
.zip(right_template.dynamic_attrs.iter())
|
.zip(right_template.dynamic_attrs.iter())
|
||||||
.for_each(|(left_attr, right_attr)| {
|
.for_each(|(left_attr, right_attr)| {
|
||||||
// Move over the ID from the old to the new
|
// Move over the ID from the old to the new
|
||||||
right_attr
|
let mounted_id = left_attr.mounted_element.get();
|
||||||
.mounted_element
|
right_attr.mounted_element.set(mounted_id);
|
||||||
.set(left_attr.mounted_element.get());
|
|
||||||
|
|
||||||
// We want to make sure anything that gets pulled is valid
|
// We want to make sure anything that gets pulled is valid
|
||||||
self.update_template(left_attr.mounted_element.get(), right_template);
|
self.update_template(left_attr.mounted_element.get(), right_template);
|
||||||
|
|
||||||
// If the attributes are different (or volatile), we need to update them
|
match (&left_attr.ty, &right_attr.ty) {
|
||||||
if left_attr.value != right_attr.value || left_attr.volatile {
|
(AttributeType::Single(left), AttributeType::Single(right)) => {
|
||||||
self.update_attribute(right_attr, left_attr);
|
self.diff_attribute(left, right, mounted_id)
|
||||||
|
}
|
||||||
|
(AttributeType::Many(left), AttributeType::Many(right)) => {
|
||||||
|
let mut left_iter = left.iter().peekable();
|
||||||
|
let mut right_iter = right.iter().peekable();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match (left_iter.peek(), right_iter.peek()) {
|
||||||
|
(Some(left), Some(right)) => {
|
||||||
|
// check which name is greater
|
||||||
|
match left.name.cmp(right.name) {
|
||||||
|
std::cmp::Ordering::Less => self.remove_attribute(
|
||||||
|
left.name,
|
||||||
|
left.namespace,
|
||||||
|
mounted_id,
|
||||||
|
),
|
||||||
|
std::cmp::Ordering::Greater => {
|
||||||
|
self.write_attribute(right, mounted_id)
|
||||||
|
}
|
||||||
|
std::cmp::Ordering::Equal => {
|
||||||
|
self.diff_attribute(left, right, mounted_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Some(_), None) => {
|
||||||
|
let left = left_iter.next().unwrap();
|
||||||
|
self.remove_attribute(left.name, left.namespace, mounted_id)
|
||||||
|
}
|
||||||
|
(None, Some(_)) => {
|
||||||
|
let right = right_iter.next().unwrap();
|
||||||
|
self.write_attribute(right, mounted_id)
|
||||||
|
}
|
||||||
|
(None, None) => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!("The macro should never generate this case"),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -138,6 +175,18 @@ impl<'b> VirtualDom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn diff_attribute(
|
||||||
|
&mut self,
|
||||||
|
left_attr: &'b Attribute<'b>,
|
||||||
|
right_attr: &'b Attribute<'b>,
|
||||||
|
id: ElementId,
|
||||||
|
) {
|
||||||
|
// If the attributes are different (or volatile), we need to update them
|
||||||
|
if left_attr.value != right_attr.value || left_attr.volatile {
|
||||||
|
self.update_attribute(right_attr, left_attr, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn diff_dynamic_node(
|
fn diff_dynamic_node(
|
||||||
&mut self,
|
&mut self,
|
||||||
left_node: &'b DynamicNode<'b>,
|
left_node: &'b DynamicNode<'b>,
|
||||||
|
@ -155,12 +204,29 @@ impl<'b> VirtualDom {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_attribute(&mut self, right_attr: &'b Attribute<'b>, left_attr: &'b Attribute) {
|
fn remove_attribute(&mut self, name: &'b str, ns: Option<&'static str>, id: ElementId) {
|
||||||
|
let name = unsafe { std::mem::transmute(name) };
|
||||||
|
let value: BorrowedAttributeValue<'b> = BorrowedAttributeValue::None;
|
||||||
|
let value = unsafe { std::mem::transmute(value) };
|
||||||
|
self.mutations.push(Mutation::SetAttribute {
|
||||||
|
id,
|
||||||
|
ns,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_attribute(
|
||||||
|
&mut self,
|
||||||
|
right_attr: &'b Attribute<'b>,
|
||||||
|
left_attr: &'b Attribute<'b>,
|
||||||
|
id: ElementId,
|
||||||
|
) {
|
||||||
let name = unsafe { std::mem::transmute(left_attr.name) };
|
let name = unsafe { std::mem::transmute(left_attr.name) };
|
||||||
let value: BorrowedAttributeValue<'b> = (&right_attr.value).into();
|
let value: BorrowedAttributeValue<'b> = (&right_attr.value).into();
|
||||||
let value = unsafe { std::mem::transmute(value) };
|
let value = unsafe { std::mem::transmute(value) };
|
||||||
self.mutations.push(Mutation::SetAttribute {
|
self.mutations.push(Mutation::SetAttribute {
|
||||||
id: left_attr.mounted_element.get(),
|
id,
|
||||||
ns: right_attr.namespace,
|
ns: right_attr.namespace,
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
|
|
|
@ -73,11 +73,11 @@ pub(crate) mod innerlude {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use crate::innerlude::{
|
pub use crate::innerlude::{
|
||||||
fc_to_builder, vdom_is_rendering, AnyValue, Attribute, AttributeValue, BorrowedAttributeValue,
|
fc_to_builder, vdom_is_rendering, AnyValue, Attribute, AttributeType, AttributeValue,
|
||||||
CapturedError, Component, DynamicNode, Element, ElementId, Event, Fragment, HasAttributesBox,
|
BorrowedAttributeValue, CapturedError, Component, DynamicNode, Element, ElementId, Event,
|
||||||
IntoDynNode, LazyNodes, Mutation, Mutations, Properties, RenderReturn, Scope, ScopeId,
|
Fragment, HasAttributesBox, IntoDynNode, LazyNodes, MountedAttribute, Mutation, Mutations,
|
||||||
ScopeState, Scoped, TaskId, Template, TemplateAttribute, TemplateNode, VComponent, VNode,
|
Properties, RenderReturn, Scope, ScopeId, ScopeState, Scoped, TaskId, Template,
|
||||||
VPlaceholder, VText, VirtualDom,
|
TemplateAttribute, TemplateNode, VComponent, VNode, VPlaceholder, VText, VirtualDom,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The purpose of this module is to alleviate imports of many common types
|
/// The purpose of this module is to alleviate imports of many common types
|
||||||
|
@ -88,9 +88,9 @@ pub mod prelude {
|
||||||
consume_context, consume_context_from_scope, current_scope_id, fc_to_builder, has_context,
|
consume_context, consume_context_from_scope, current_scope_id, fc_to_builder, has_context,
|
||||||
provide_context, provide_context_to_scope, provide_root_context, push_future,
|
provide_context, provide_context_to_scope, provide_root_context, push_future,
|
||||||
remove_future, schedule_update_any, spawn, spawn_forever, suspend, throw, AnyValue,
|
remove_future, schedule_update_any, spawn, spawn_forever, suspend, throw, AnyValue,
|
||||||
Component, Element, Event, EventHandler, Fragment, IntoAttributeValue, LazyNodes,
|
AttributeType, Component, Element, Event, EventHandler, Fragment, IntoAttributeValue,
|
||||||
Properties, Scope, ScopeId, ScopeState, Scoped, TaskId, Template, TemplateAttribute,
|
LazyNodes, MountedAttribute, Properties, Scope, ScopeId, ScopeState, Scoped, TaskId,
|
||||||
TemplateNode, Throw, VNode, VirtualDom,
|
Template, TemplateAttribute, TemplateNode, Throw, VNode, VirtualDom,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ pub struct VNode<'a> {
|
||||||
pub dynamic_nodes: &'a [DynamicNode<'a>],
|
pub dynamic_nodes: &'a [DynamicNode<'a>],
|
||||||
|
|
||||||
/// The dynamic parts of the template
|
/// The dynamic parts of the template
|
||||||
pub dynamic_attrs: &'a [Attribute<'a>],
|
pub dynamic_attrs: &'a [MountedAttribute<'a>],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VNode<'a> {
|
impl<'a> VNode<'a> {
|
||||||
|
@ -414,6 +414,44 @@ pub enum TemplateAttribute<'a> {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MountedAttribute<'a> {
|
||||||
|
pub(crate) ty: AttributeType<'a>,
|
||||||
|
|
||||||
|
/// The element in the DOM that this attribute belongs to
|
||||||
|
pub(crate) mounted_element: Cell<ElementId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<Attribute<'a>> for MountedAttribute<'a> {
|
||||||
|
fn from(attr: Attribute<'a>) -> Self {
|
||||||
|
Self {
|
||||||
|
ty: AttributeType::Single(attr),
|
||||||
|
mounted_element: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a [Attribute<'a>]> for MountedAttribute<'a> {
|
||||||
|
fn from(attr: &'a [Attribute<'a>]) -> Self {
|
||||||
|
Self {
|
||||||
|
ty: AttributeType::Many(attr),
|
||||||
|
mounted_element: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> MountedAttribute<'a> {
|
||||||
|
/// Get the type of this attribute
|
||||||
|
pub fn attribute_type(&self) -> &AttributeType<'a> {
|
||||||
|
&self.ty
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the element that this attribute is mounted to
|
||||||
|
pub fn mounted_element(&self) -> ElementId {
|
||||||
|
self.mounted_element.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An attribute on a DOM node, such as `id="my-thing"` or `href="https://example.com"`
|
/// An attribute on a DOM node, such as `id="my-thing"` or `href="https://example.com"`
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Attribute<'a> {
|
pub struct Attribute<'a> {
|
||||||
|
@ -430,9 +468,6 @@ pub struct Attribute<'a> {
|
||||||
|
|
||||||
/// An indication of we should always try and set the attribute. Used in controlled components to ensure changes are propagated
|
/// An indication of we should always try and set the attribute. Used in controlled components to ensure changes are propagated
|
||||||
pub volatile: bool,
|
pub volatile: bool,
|
||||||
|
|
||||||
/// The element in the DOM that this attribute belongs to
|
|
||||||
pub(crate) mounted_element: Cell<ElementId>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Attribute<'a> {
|
impl<'a> Attribute<'a> {
|
||||||
|
@ -448,13 +483,38 @@ impl<'a> Attribute<'a> {
|
||||||
value,
|
value,
|
||||||
namespace,
|
namespace,
|
||||||
volatile,
|
volatile,
|
||||||
mounted_element: Cell::new(ElementId::default()),
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AttributeType<'a> {
|
||||||
|
Single(Attribute<'a>),
|
||||||
|
/// Many different attributes sorted by name
|
||||||
|
Many(&'a [Attribute<'a>]),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AttributeType<'a> {
|
||||||
|
/// Call the given function on each attribute
|
||||||
|
pub fn for_each<'b, F>(&'b self, mut f: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&'b Attribute<'a>),
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Single(attr) => f(attr),
|
||||||
|
Self::Many(attrs) => attrs.iter().for_each(f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the element that this attribute is mounted to
|
/// Try to call the given function on each attribute
|
||||||
pub fn mounted_element(&self) -> ElementId {
|
pub fn try_for_each<'b, F, E>(&'b self, mut f: F) -> Result<(), E>
|
||||||
self.mounted_element.get()
|
where
|
||||||
|
F: FnMut(&'b Attribute<'a>) -> Result<(), E>,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Single(attr) => f(attr),
|
||||||
|
Self::Many(attrs) => attrs.iter().try_for_each(f),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,8 @@ use crate::{
|
||||||
nodes::{IntoAttributeValue, IntoDynNode, RenderReturn},
|
nodes::{IntoAttributeValue, IntoDynNode, RenderReturn},
|
||||||
runtime::Runtime,
|
runtime::Runtime,
|
||||||
scope_context::ScopeContext,
|
scope_context::ScopeContext,
|
||||||
AnyValue, Attribute, AttributeValue, Element, Event, Properties, TaskId,
|
AnyValue, Attribute, AttributeType, AttributeValue, Element, Event, MountedAttribute,
|
||||||
|
Properties, TaskId,
|
||||||
};
|
};
|
||||||
use bumpalo::{boxed::Box as BumpBox, Bump};
|
use bumpalo::{boxed::Box as BumpBox, Bump};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -335,14 +336,10 @@ impl<'src> ScopeState {
|
||||||
|
|
||||||
let mut listeners = self.attributes_to_drop.borrow_mut();
|
let mut listeners = self.attributes_to_drop.borrow_mut();
|
||||||
for attr in element.dynamic_attrs {
|
for attr in element.dynamic_attrs {
|
||||||
match attr.value {
|
attr.ty.for_each(|attr| {
|
||||||
AttributeValue::Any(_) | AttributeValue::Listener(_) => {
|
let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) };
|
||||||
let unbounded = unsafe { std::mem::transmute(attr as *const Attribute) };
|
listeners.push(unbounded);
|
||||||
listeners.push(unbounded);
|
})
|
||||||
}
|
|
||||||
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut props = self.borrowed_props.borrow_mut();
|
let mut props = self.borrowed_props.borrow_mut();
|
||||||
|
@ -393,13 +390,15 @@ impl<'src> ScopeState {
|
||||||
value: impl IntoAttributeValue<'src>,
|
value: impl IntoAttributeValue<'src>,
|
||||||
namespace: Option<&'static str>,
|
namespace: Option<&'static str>,
|
||||||
volatile: bool,
|
volatile: bool,
|
||||||
) -> Attribute<'src> {
|
) -> MountedAttribute<'src> {
|
||||||
Attribute {
|
MountedAttribute {
|
||||||
name,
|
ty: AttributeType::Single(Attribute {
|
||||||
namespace,
|
name,
|
||||||
volatile,
|
namespace,
|
||||||
|
volatile,
|
||||||
|
value: value.into_value(self.bump()),
|
||||||
|
}),
|
||||||
mounted_element: Default::default(),
|
mounted_element: Default::default(),
|
||||||
value: value.into_value(self.bump()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
any_props::VProps,
|
any_props::VProps,
|
||||||
arena::{ElementId, ElementRef},
|
arena::{ElementId, ElementRef},
|
||||||
innerlude::{DirtyScope, ErrorBoundary, Mutations, Scheduler, SchedulerMsg},
|
innerlude::{AttributeType, DirtyScope, ErrorBoundary, Mutations, Scheduler, SchedulerMsg},
|
||||||
mutations::Mutation,
|
mutations::Mutation,
|
||||||
nodes::RenderReturn,
|
nodes::RenderReturn,
|
||||||
nodes::{Template, TemplateId},
|
nodes::{Template, TemplateId},
|
||||||
runtime::{Runtime, RuntimeGuard},
|
runtime::{Runtime, RuntimeGuard},
|
||||||
scopes::{ScopeId, ScopeState},
|
scopes::{ScopeId, ScopeState},
|
||||||
AttributeValue, Element, Event, Scope,
|
Attribute, AttributeValue, Element, Event, Scope,
|
||||||
};
|
};
|
||||||
use futures_util::{pin_mut, StreamExt};
|
use futures_util::{pin_mut, StreamExt};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
@ -371,12 +371,30 @@ impl VirtualDom {
|
||||||
for (idx, attr) in template.dynamic_attrs.iter().enumerate() {
|
for (idx, attr) in template.dynamic_attrs.iter().enumerate() {
|
||||||
let this_path = node_template.attr_paths[idx];
|
let this_path = node_template.attr_paths[idx];
|
||||||
|
|
||||||
// Remove the "on" prefix if it exists, TODO, we should remove this and settle on one
|
fn add_listener<'a>(
|
||||||
if attr.name.trim_start_matches("on") == name
|
attribute: &'a Attribute<'a>,
|
||||||
&& target_path.is_decendant(&this_path)
|
event_name: &str,
|
||||||
{
|
listeners: &mut Vec<&'a AttributeValue<'a>>,
|
||||||
listeners.push(&attr.value);
|
) {
|
||||||
|
if attribute.name.trim_start_matches("on") == event_name {
|
||||||
|
listeners.push(&attribute.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
listeners.push(&attribute.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the "on" prefix if it exists, TODO, we should remove this and settle on one
|
||||||
|
if target_path.is_decendant(&this_path) {
|
||||||
|
match &attr.ty {
|
||||||
|
AttributeType::Single(attribute) => {
|
||||||
|
add_listener(attribute, name, &mut listeners);
|
||||||
|
}
|
||||||
|
AttributeType::Many(attributes) => {
|
||||||
|
for attribute in *attributes {
|
||||||
|
add_listener(attribute, name, &mut listeners);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Break if this is the exact target element.
|
// Break if this is the exact target element.
|
||||||
// This means we won't call two listeners with the same name on the same element. This should be
|
// This means we won't call two listeners with the same name on the same element. This should be
|
||||||
// documented, or be rejected from the rsx! macro outright
|
// documented, or be rejected from the rsx! macro outright
|
||||||
|
@ -422,20 +440,57 @@ impl VirtualDom {
|
||||||
for (idx, attr) in template.dynamic_attrs.iter().enumerate() {
|
for (idx, attr) in template.dynamic_attrs.iter().enumerate() {
|
||||||
let this_path = node_template.attr_paths[idx];
|
let this_path = node_template.attr_paths[idx];
|
||||||
|
|
||||||
// Remove the "on" prefix if it exists, TODO, we should remove this and settle on one
|
fn call_listener(
|
||||||
// Only call the listener if this is the exact target element.
|
attribute: &Attribute,
|
||||||
if attr.name.trim_start_matches("on") == name && target_path == this_path {
|
event_name: &str,
|
||||||
if let AttributeValue::Listener(listener) = &attr.value {
|
uievent: &Event<dyn Any>,
|
||||||
let origin = el_ref.scope;
|
runtime: &Runtime,
|
||||||
self.runtime.scope_stack.borrow_mut().push(origin);
|
origin: ScopeId,
|
||||||
self.runtime.rendering.set(false);
|
) -> bool {
|
||||||
if let Some(cb) = listener.borrow_mut().as_deref_mut() {
|
// Remove the "on" prefix if it exists, TODO, we should remove this and settle on one
|
||||||
cb(uievent.clone());
|
// Only call the listener if this is the exact target element.
|
||||||
}
|
if attribute.name.trim_start_matches("on") == event_name {
|
||||||
self.runtime.scope_stack.borrow_mut().pop();
|
if let AttributeValue::Listener(listener) = &attribute.value {
|
||||||
self.runtime.rendering.set(true);
|
runtime.scope_stack.borrow_mut().push(origin);
|
||||||
|
runtime.rendering.set(false);
|
||||||
|
if let Some(cb) = listener.borrow_mut().as_deref_mut() {
|
||||||
|
cb(uievent.clone());
|
||||||
|
}
|
||||||
|
runtime.scope_stack.borrow_mut().pop();
|
||||||
|
runtime.rendering.set(true);
|
||||||
|
|
||||||
break;
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
if target_path == this_path {
|
||||||
|
match &attr.ty {
|
||||||
|
AttributeType::Single(attribute) => {
|
||||||
|
if call_listener(
|
||||||
|
attribute,
|
||||||
|
name,
|
||||||
|
&uievent,
|
||||||
|
&self.runtime,
|
||||||
|
el_ref.scope,
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AttributeType::Many(attributes) => {
|
||||||
|
for attribute in *attributes {
|
||||||
|
if call_listener(
|
||||||
|
attribute,
|
||||||
|
name,
|
||||||
|
&uievent,
|
||||||
|
&self.runtime,
|
||||||
|
el_ref.scope,
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#![cfg(not(miri))]
|
#![cfg(not(miri))]
|
||||||
|
|
||||||
use dioxus::prelude::Props;
|
use dioxus::prelude::Props;
|
||||||
use dioxus_core::*;
|
use dioxus_core::{MountedAttribute, *};
|
||||||
use std::{cell::Cell, collections::HashSet};
|
use std::{cell::Cell, collections::HashSet};
|
||||||
|
|
||||||
fn random_ns() -> Option<&'static str> {
|
fn random_ns() -> Option<&'static str> {
|
||||||
|
@ -205,7 +205,7 @@ fn create_random_dynamic_node(cx: &ScopeState, depth: usize) -> DynamicNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute {
|
fn create_random_dynamic_attr(cx: &ScopeState) -> MountedAttribute {
|
||||||
let value = match rand::random::<u8>() % 7 {
|
let value = match rand::random::<u8>() % 7 {
|
||||||
0 => AttributeValue::Text(Box::leak(
|
0 => AttributeValue::Text(Box::leak(
|
||||||
format!("{}", rand::random::<usize>()).into_boxed_str(),
|
format!("{}", rand::random::<usize>()).into_boxed_str(),
|
||||||
|
@ -217,7 +217,7 @@ fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute {
|
||||||
5 => AttributeValue::None,
|
5 => AttributeValue::None,
|
||||||
6 => {
|
6 => {
|
||||||
let value = cx.listener(|e: Event<String>| println!("{:?}", e));
|
let value = cx.listener(|e: Event<String>| println!("{:?}", e));
|
||||||
return Attribute::new("ondata", value, None, false);
|
return Attribute::new("ondata", value, None, false).into();
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
@ -227,6 +227,7 @@ fn create_random_dynamic_attr(cx: &ScopeState) -> Attribute {
|
||||||
random_ns(),
|
random_ns(),
|
||||||
rand::random(),
|
rand::random(),
|
||||||
)
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut TEMPLATE_COUNT: usize = 0;
|
static mut TEMPLATE_COUNT: usize = 0;
|
||||||
|
|
|
@ -164,7 +164,7 @@ fn props_spread() {
|
||||||
static TEMPLATE: ::dioxus::core::Template = ::dioxus::core::Template { name: concat!(file!(), ":", line!(), ":", column!(), ":", "" ), roots: &[::dioxus::core::TemplateNode::Element { tag: dioxus_elements::audio::TAG_NAME, namespace: dioxus_elements::audio::NAME_SPACE, attrs: &[::dioxus::core::TemplateAttribute::Dynamic { id: 0usize }], children: &[] }], node_paths: &[], attr_paths: &[&[0u8]] };
|
static TEMPLATE: ::dioxus::core::Template = ::dioxus::core::Template { name: concat!(file!(), ":", line!(), ":", column!(), ":", "" ), roots: &[::dioxus::core::TemplateNode::Element { tag: dioxus_elements::audio::TAG_NAME, namespace: dioxus_elements::audio::NAME_SPACE, attrs: &[::dioxus::core::TemplateAttribute::Dynamic { id: 0usize }], children: &[] }], node_paths: &[], attr_paths: &[&[0u8]] };
|
||||||
let mut attrs = vec![__cx.attr(dioxus_elements::audio::muted.0, muted, dioxus_elements::audio::muted.1, dioxus_elements::audio::muted.2)];
|
let mut attrs = vec![__cx.attr(dioxus_elements::audio::muted.0, muted, dioxus_elements::audio::muted.1, dioxus_elements::audio::muted.2)];
|
||||||
for attr in attributes {
|
for attr in attributes {
|
||||||
attrs.push(__cx.attr(attr.name, attr.value.into_value(__cx.bump()), attr.namespace, attr.volatile));
|
attrs.push(attr);
|
||||||
}
|
}
|
||||||
::dioxus::core::VNode {
|
::dioxus::core::VNode {
|
||||||
parent: None,
|
parent: None,
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -9,7 +9,7 @@ macro_rules! impl_event {
|
||||||
$(
|
$(
|
||||||
$( #[$attr] )*
|
$( #[$attr] )*
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn $name<'a, E: crate::EventReturn<T>, T>(_cx: &'a ::dioxus_core::ScopeState, mut _f: impl FnMut(::dioxus_core::Event<$data>) -> E + 'a) -> ::dioxus_core::Attribute<'a> {
|
pub fn $name<'a, E: crate::EventReturn<T>, T>(_cx: &'a ::dioxus_core::ScopeState, mut _f: impl FnMut(::dioxus_core::Event<$data>) -> E + 'a) -> ::dioxus_core::MountedAttribute<'a> {
|
||||||
::dioxus_core::Attribute::new(
|
::dioxus_core::Attribute::new(
|
||||||
stringify!($name),
|
stringify!($name),
|
||||||
_cx.listener(move |e: ::dioxus_core::Event<$data>| {
|
_cx.listener(move |e: ::dioxus_core::Event<$data>| {
|
||||||
|
@ -17,7 +17,7 @@ macro_rules! impl_event {
|
||||||
}),
|
}),
|
||||||
None,
|
None,
|
||||||
false,
|
false,
|
||||||
)
|
).into()
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
};
|
};
|
||||||
|
|
|
@ -167,7 +167,7 @@ impl Parse for Element {
|
||||||
attributes,
|
attributes,
|
||||||
children,
|
children,
|
||||||
brace,
|
brace,
|
||||||
extra_attributes
|
extra_attributes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -397,11 +397,3 @@ impl ToTokens for ElementAttrNamed {
|
||||||
tokens.append_all(attribute);
|
tokens.append_all(attribute);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ::dioxus::core::Attribute {
|
|
||||||
// name: stringify!(#name),
|
|
||||||
// namespace: None,
|
|
||||||
// volatile: false,
|
|
||||||
// mounted_node: Default::default(),
|
|
||||||
// value: ::dioxus::core::AttributeValue::Text(#value),
|
|
||||||
// }
|
|
||||||
|
|
|
@ -79,23 +79,31 @@ impl Renderer {
|
||||||
match segment {
|
match segment {
|
||||||
Segment::Attr(idx) => {
|
Segment::Attr(idx) => {
|
||||||
let attr = &template.dynamic_attrs[*idx];
|
let attr = &template.dynamic_attrs[*idx];
|
||||||
if attr.name == "dangerous_inner_html" {
|
attr.attribute_type().try_for_each(|attr| {
|
||||||
inner_html = Some(attr);
|
if attr.name == "dangerous_inner_html" {
|
||||||
} else if attr.namespace == Some("style") {
|
inner_html = Some(attr);
|
||||||
accumulated_dynamic_styles.push(attr);
|
} else if attr.namespace == Some("style") {
|
||||||
} else {
|
accumulated_dynamic_styles.push(attr);
|
||||||
match attr.value {
|
} else {
|
||||||
AttributeValue::Text(value) => {
|
match attr.value {
|
||||||
write!(buf, " {}=\"{}\"", attr.name, value)?
|
AttributeValue::Text(value) => {
|
||||||
}
|
write!(buf, " {}=\"{}\"", attr.name, value)?
|
||||||
AttributeValue::Bool(value) => write!(buf, " {}={}", attr.name, value)?,
|
}
|
||||||
AttributeValue::Int(value) => write!(buf, " {}={}", attr.name, value)?,
|
AttributeValue::Bool(value) => {
|
||||||
AttributeValue::Float(value) => {
|
write!(buf, " {}={}", attr.name, value)?
|
||||||
write!(buf, " {}={}", attr.name, value)?
|
}
|
||||||
}
|
AttributeValue::Int(value) => {
|
||||||
_ => {}
|
write!(buf, " {}={}", attr.name, value)?
|
||||||
};
|
}
|
||||||
}
|
AttributeValue::Float(value) => {
|
||||||
|
write!(buf, " {}={}", attr.name, value)?
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
}
|
}
|
||||||
Segment::Node(idx) => match &template.dynamic_nodes[*idx] {
|
Segment::Node(idx) => match &template.dynamic_nodes[*idx] {
|
||||||
DynamicNode::Component(node) => {
|
DynamicNode::Component(node) => {
|
||||||
|
|
Loading…
Reference in a new issue