mirror of https://github.com/yewstack/yew
Add component and parent access to scope (#1151)
* Add reference to parent to scope * Add untyped scope
This commit is contained in:
parent
404ff77ffb
commit
9c0951513d
|
@ -89,7 +89,7 @@ where
|
|||
{
|
||||
/// Creates a new `App` with a component in a context.
|
||||
pub fn new() -> Self {
|
||||
let scope = Scope::new();
|
||||
let scope = Scope::new(None);
|
||||
App { scope }
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@ mod listener;
|
|||
mod scope;
|
||||
|
||||
pub use listener::*;
|
||||
pub use scope::Scope;
|
||||
pub(crate) use scope::{AnyScope, ComponentUpdate};
|
||||
pub(crate) use scope::ComponentUpdate;
|
||||
pub use scope::{AnyScope, Scope};
|
||||
|
||||
use crate::callback::Callback;
|
||||
use crate::virtual_dom::{VChild, VList, VNode};
|
||||
|
|
|
@ -2,9 +2,10 @@ use super::{Callback, Component, NodeRef, Renderable};
|
|||
use crate::scheduler::{scheduler, ComponentRunnableType, Runnable, Shared};
|
||||
use crate::virtual_dom::{VDiff, VNode};
|
||||
use cfg_if::cfg_if;
|
||||
use std::any::Any;
|
||||
use std::cell::RefCell;
|
||||
use std::any::{Any, TypeId};
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "std_web")] {
|
||||
|
@ -24,9 +25,62 @@ pub(crate) enum ComponentUpdate<COMP: Component> {
|
|||
Properties(COMP::Properties, NodeRef),
|
||||
}
|
||||
|
||||
/// Untyped scope used for accessing parent scope
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AnyScope {
|
||||
type_id: TypeId,
|
||||
parent: Option<Rc<AnyScope>>,
|
||||
state: Rc<dyn Any>,
|
||||
}
|
||||
|
||||
impl Default for AnyScope {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
type_id: TypeId::of::<()>(),
|
||||
parent: None,
|
||||
state: Rc::new(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> From<Scope<COMP>> for AnyScope {
|
||||
fn from(scope: Scope<COMP>) -> Self {
|
||||
AnyScope {
|
||||
type_id: TypeId::of::<COMP>(),
|
||||
parent: scope.parent,
|
||||
state: Rc::new(scope.state),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AnyScope {
|
||||
/// Returns the parent scope
|
||||
pub fn get_parent(&self) -> Option<&AnyScope> {
|
||||
self.parent.as_deref()
|
||||
}
|
||||
|
||||
/// Returns the type of the linked component
|
||||
pub fn get_type_id(&self) -> &TypeId {
|
||||
&self.type_id
|
||||
}
|
||||
|
||||
/// Attempts to downcast into a typed scope
|
||||
pub fn downcast<COMP: Component>(self) -> Scope<COMP> {
|
||||
Scope {
|
||||
parent: self.parent,
|
||||
state: self
|
||||
.state
|
||||
.downcast_ref::<Shared<ComponentState<COMP>>>()
|
||||
.expect("unexpected component type")
|
||||
.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A context which allows sending messages to a component.
|
||||
pub struct Scope<COMP: Component> {
|
||||
shared_state: Shared<ComponentState<COMP>>,
|
||||
parent: Option<Rc<AnyScope>>,
|
||||
state: Shared<ComponentState<COMP>>,
|
||||
}
|
||||
|
||||
impl<COMP: Component> fmt::Debug for Scope<COMP> {
|
||||
|
@ -38,22 +92,30 @@ impl<COMP: Component> fmt::Debug for Scope<COMP> {
|
|||
impl<COMP: Component> Clone for Scope<COMP> {
|
||||
fn clone(&self) -> Self {
|
||||
Scope {
|
||||
shared_state: self.shared_state.clone(),
|
||||
parent: self.parent.clone(),
|
||||
state: self.state.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> Default for Scope<COMP> {
|
||||
fn default() -> Self {
|
||||
Scope::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> Scope<COMP> {
|
||||
/// visible for testing
|
||||
pub fn new() -> Self {
|
||||
let shared_state = Rc::new(RefCell::new(ComponentState::Empty));
|
||||
Scope { shared_state }
|
||||
/// Returns the parent scope
|
||||
pub fn get_parent(&self) -> Option<&AnyScope> {
|
||||
self.parent.as_deref()
|
||||
}
|
||||
|
||||
/// Returns the linked component if available
|
||||
pub fn get_component(&self) -> Option<impl Deref<Target = COMP> + '_> {
|
||||
self.state.try_borrow().ok().and_then(|state_ref| {
|
||||
state_ref.component()?;
|
||||
Some(Ref::map(state_ref, |this| this.component().unwrap()))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn new(parent: Option<AnyScope>) -> Self {
|
||||
let parent = parent.map(Rc::new);
|
||||
let state = Rc::new(RefCell::new(ComponentState::Empty));
|
||||
Scope { parent, state }
|
||||
}
|
||||
|
||||
/// Mounts a component with `props` to the specified `element` in the DOM.
|
||||
|
@ -72,15 +134,15 @@ impl<COMP: Component> Scope<COMP> {
|
|||
props,
|
||||
ancestor,
|
||||
};
|
||||
*scope.shared_state.borrow_mut() = ComponentState::Ready(ready_state);
|
||||
*scope.state.borrow_mut() = ComponentState::Ready(ready_state);
|
||||
scope.create();
|
||||
scope
|
||||
}
|
||||
|
||||
/// Schedules a task to create and render a component and then mount it to the DOM
|
||||
pub(crate) fn create(&mut self) {
|
||||
let shared_state = self.shared_state.clone();
|
||||
let create = CreateComponent { shared_state };
|
||||
let state = self.state.clone();
|
||||
let create = CreateComponent { state };
|
||||
scheduler().push_comp(ComponentRunnableType::Create, Box::new(create));
|
||||
self.rendered(true);
|
||||
}
|
||||
|
@ -88,7 +150,7 @@ impl<COMP: Component> Scope<COMP> {
|
|||
/// Schedules a task to send a message or new props to a component
|
||||
pub(crate) fn update(&self, update: ComponentUpdate<COMP>) {
|
||||
let update = UpdateComponent {
|
||||
shared_state: self.shared_state.clone(),
|
||||
state: self.state.clone(),
|
||||
update,
|
||||
};
|
||||
scheduler().push_comp(ComponentRunnableType::Update, Box::new(update));
|
||||
|
@ -97,9 +159,9 @@ impl<COMP: Component> Scope<COMP> {
|
|||
|
||||
/// Schedules a task to call the rendered method on a component
|
||||
pub(crate) fn rendered(&self, first_render: bool) {
|
||||
let shared_state = self.shared_state.clone();
|
||||
let state = self.state.clone();
|
||||
let rendered = RenderedComponent {
|
||||
shared_state,
|
||||
state,
|
||||
first_render,
|
||||
};
|
||||
scheduler().push_comp(ComponentRunnableType::Rendered, Box::new(rendered));
|
||||
|
@ -107,8 +169,8 @@ impl<COMP: Component> Scope<COMP> {
|
|||
|
||||
/// Schedules a task to destroy a component
|
||||
pub(crate) fn destroy(&mut self) {
|
||||
let shared_state = self.shared_state.clone();
|
||||
let destroy = DestroyComponent { shared_state };
|
||||
let state = self.state.clone();
|
||||
let destroy = DestroyComponent { state };
|
||||
scheduler().push_comp(ComponentRunnableType::Destroy, Box::new(destroy));
|
||||
}
|
||||
|
||||
|
@ -180,6 +242,15 @@ enum ComponentState<COMP: Component> {
|
|||
Destroyed,
|
||||
}
|
||||
|
||||
impl<COMP: Component> ComponentState<COMP> {
|
||||
fn component(&self) -> Option<&COMP> {
|
||||
match self {
|
||||
ComponentState::Created(state) => Some(&state.component),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<COMP: Component> fmt::Display for ComponentState<COMP> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let name = match self {
|
||||
|
@ -205,10 +276,11 @@ impl<COMP: Component> ReadyState<COMP> {
|
|||
fn create(self) -> CreatedState<COMP> {
|
||||
CreatedState {
|
||||
rendered: false,
|
||||
component: COMP::create(self.props, self.scope),
|
||||
component: COMP::create(self.props, self.scope.clone()),
|
||||
element: self.element,
|
||||
last_frame: self.ancestor,
|
||||
node_ref: self.node_ref,
|
||||
scope: self.scope,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -219,6 +291,7 @@ struct CreatedState<COMP: Component> {
|
|||
component: COMP,
|
||||
last_frame: Option<VNode>,
|
||||
node_ref: NodeRef,
|
||||
scope: Scope<COMP>,
|
||||
}
|
||||
|
||||
impl<COMP: Component> CreatedState<COMP> {
|
||||
|
@ -231,7 +304,12 @@ impl<COMP: Component> CreatedState<COMP> {
|
|||
|
||||
fn update(mut self) -> Self {
|
||||
let mut root = self.component.render();
|
||||
if let Some(node) = root.apply(&self.element, None, self.last_frame) {
|
||||
if let Some(node) = root.apply(
|
||||
&self.scope.clone().into(),
|
||||
&self.element,
|
||||
None,
|
||||
self.last_frame,
|
||||
) {
|
||||
self.node_ref.set(Some(node));
|
||||
} else if let VNode::VComp(child) = &root {
|
||||
// If the root VNode is a VComp, we won't have access to the rendered DOM node
|
||||
|
@ -249,7 +327,7 @@ struct RenderedComponent<COMP>
|
|||
where
|
||||
COMP: Component,
|
||||
{
|
||||
shared_state: Shared<ComponentState<COMP>>,
|
||||
state: Shared<ComponentState<COMP>>,
|
||||
first_render: bool,
|
||||
}
|
||||
|
||||
|
@ -258,8 +336,8 @@ where
|
|||
COMP: Component,
|
||||
{
|
||||
fn run(self: Box<Self>) {
|
||||
let current_state = self.shared_state.replace(ComponentState::Processing);
|
||||
self.shared_state.replace(match current_state {
|
||||
let current_state = self.state.replace(ComponentState::Processing);
|
||||
self.state.replace(match current_state {
|
||||
ComponentState::Created(s) if !s.rendered => {
|
||||
ComponentState::Created(s.rendered(self.first_render))
|
||||
}
|
||||
|
@ -275,7 +353,7 @@ struct CreateComponent<COMP>
|
|||
where
|
||||
COMP: Component,
|
||||
{
|
||||
shared_state: Shared<ComponentState<COMP>>,
|
||||
state: Shared<ComponentState<COMP>>,
|
||||
}
|
||||
|
||||
impl<COMP> Runnable for CreateComponent<COMP>
|
||||
|
@ -283,8 +361,8 @@ where
|
|||
COMP: Component,
|
||||
{
|
||||
fn run(self: Box<Self>) {
|
||||
let current_state = self.shared_state.replace(ComponentState::Processing);
|
||||
self.shared_state.replace(match current_state {
|
||||
let current_state = self.state.replace(ComponentState::Processing);
|
||||
self.state.replace(match current_state {
|
||||
ComponentState::Ready(s) => ComponentState::Created(s.create().update()),
|
||||
ComponentState::Created(_) | ComponentState::Destroyed => current_state,
|
||||
ComponentState::Empty | ComponentState::Processing => {
|
||||
|
@ -298,7 +376,7 @@ struct DestroyComponent<COMP>
|
|||
where
|
||||
COMP: Component,
|
||||
{
|
||||
shared_state: Shared<ComponentState<COMP>>,
|
||||
state: Shared<ComponentState<COMP>>,
|
||||
}
|
||||
|
||||
impl<COMP> Runnable for DestroyComponent<COMP>
|
||||
|
@ -306,7 +384,7 @@ where
|
|||
COMP: Component,
|
||||
{
|
||||
fn run(self: Box<Self>) {
|
||||
match self.shared_state.replace(ComponentState::Destroyed) {
|
||||
match self.state.replace(ComponentState::Destroyed) {
|
||||
ComponentState::Created(mut this) => {
|
||||
this.component.destroy();
|
||||
if let Some(last_frame) = &mut this.last_frame {
|
||||
|
@ -328,7 +406,7 @@ struct UpdateComponent<COMP>
|
|||
where
|
||||
COMP: Component,
|
||||
{
|
||||
shared_state: Shared<ComponentState<COMP>>,
|
||||
state: Shared<ComponentState<COMP>>,
|
||||
update: ComponentUpdate<COMP>,
|
||||
}
|
||||
|
||||
|
@ -337,8 +415,8 @@ where
|
|||
COMP: Component,
|
||||
{
|
||||
fn run(self: Box<Self>) {
|
||||
let current_state = self.shared_state.replace(ComponentState::Processing);
|
||||
self.shared_state.replace(match current_state {
|
||||
let current_state = self.state.replace(ComponentState::Processing);
|
||||
self.state.replace(match current_state {
|
||||
ComponentState::Created(mut this) => {
|
||||
let should_update = match self.update {
|
||||
ComponentUpdate::Message(message) => this.component.update(message),
|
||||
|
@ -367,24 +445,3 @@ where
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct AnyScope {
|
||||
scope: Box<dyn Any>,
|
||||
}
|
||||
|
||||
impl<COMP: Component> From<Scope<COMP>> for AnyScope {
|
||||
fn from(scope: Scope<COMP>) -> Self {
|
||||
AnyScope {
|
||||
scope: Box::new(scope),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AnyScope {
|
||||
pub(crate) fn downcast<COMP: Component>(&self) -> Scope<COMP> {
|
||||
self.scope
|
||||
.downcast_ref::<Scope<COMP>>()
|
||||
.expect("INTERNAL: unexpected component type, please report")
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ pub mod vtag;
|
|||
#[doc(hidden)]
|
||||
pub mod vtext;
|
||||
|
||||
use crate::html::AnyScope;
|
||||
use cfg_if::cfg_if;
|
||||
use indexmap::set::IndexSet;
|
||||
use std::collections::HashMap;
|
||||
|
@ -217,6 +218,7 @@ pub(crate) trait VDiff {
|
|||
/// (always removes the `Node` that exists).
|
||||
fn apply(
|
||||
&mut self,
|
||||
scope: &AnyScope,
|
||||
parent: &Element,
|
||||
previous_sibling: Option<&Node>,
|
||||
ancestor: Option<VNode>,
|
||||
|
|
|
@ -21,7 +21,7 @@ type Generator = dyn Fn(GeneratorType) -> Mounted;
|
|||
|
||||
/// Components can be generated by mounting or by overwriting an old component.
|
||||
enum GeneratorType {
|
||||
Mount(Element, TextNode),
|
||||
Mount(AnyScope, Element, TextNode),
|
||||
Overwrite(AnyScope),
|
||||
}
|
||||
|
||||
|
@ -111,8 +111,8 @@ impl VComp {
|
|||
let node_ref_clone = node_ref.clone();
|
||||
let generator = move |generator_type: GeneratorType| -> Mounted {
|
||||
match generator_type {
|
||||
GeneratorType::Mount(element, dummy_node) => {
|
||||
let scope: Scope<COMP> = Scope::new();
|
||||
GeneratorType::Mount(parent_scope, element, dummy_node) => {
|
||||
let scope: Scope<COMP> = Scope::new(Some(parent_scope));
|
||||
|
||||
let mut scope = scope.mount_in_place(
|
||||
element,
|
||||
|
@ -156,8 +156,8 @@ impl VComp {
|
|||
|
||||
impl Unmounted {
|
||||
/// Mount a virtual component using a generator.
|
||||
fn mount(self, parent: Element, dummy_node: TextNode) -> Mounted {
|
||||
(self.generator)(GeneratorType::Mount(parent, dummy_node))
|
||||
fn mount(self, parent_scope: AnyScope, parent: Element, dummy_node: TextNode) -> Mounted {
|
||||
(self.generator)(GeneratorType::Mount(parent_scope, parent, dummy_node))
|
||||
}
|
||||
|
||||
/// Overwrite an existing virtual component using a generator.
|
||||
|
@ -186,6 +186,7 @@ impl VDiff for VComp {
|
|||
|
||||
fn apply(
|
||||
&mut self,
|
||||
scope: &AnyScope,
|
||||
parent: &Element,
|
||||
previous_sibling: Option<&Node>,
|
||||
ancestor: Option<VNode>,
|
||||
|
@ -246,7 +247,7 @@ impl VDiff for VComp {
|
|||
result.expect("can't append node to parent");
|
||||
}
|
||||
}
|
||||
this.mount(parent.to_owned(), dummy_node)
|
||||
this.mount(scope.clone(), parent.to_owned(), dummy_node)
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! This module contains fragments implementation.
|
||||
use super::{VDiff, VNode, VText};
|
||||
use crate::html::AnyScope;
|
||||
use cfg_if::cfg_if;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
@ -77,6 +78,7 @@ impl VDiff for VList {
|
|||
|
||||
fn apply(
|
||||
&mut self,
|
||||
scope: &AnyScope,
|
||||
parent: &Element,
|
||||
previous_sibling: Option<&Node>,
|
||||
ancestor: Option<VNode>,
|
||||
|
@ -143,20 +145,22 @@ impl VDiff for VList {
|
|||
match rights_lookup.remove(key) {
|
||||
Some(right) => {
|
||||
previous_sibling =
|
||||
left.apply(parent, previous_sibling.as_ref(), Some(right));
|
||||
left.apply(scope, parent, previous_sibling.as_ref(), Some(right));
|
||||
}
|
||||
None => {
|
||||
previous_sibling = left.apply(parent, previous_sibling.as_ref(), None);
|
||||
previous_sibling =
|
||||
left.apply(scope, parent, previous_sibling.as_ref(), None);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match rights.next() {
|
||||
Some(right) => {
|
||||
previous_sibling =
|
||||
left.apply(parent, previous_sibling.as_ref(), Some(right));
|
||||
left.apply(scope, parent, previous_sibling.as_ref(), Some(right));
|
||||
}
|
||||
None => {
|
||||
previous_sibling = left.apply(parent, previous_sibling.as_ref(), None);
|
||||
previous_sibling =
|
||||
left.apply(scope, parent, previous_sibling.as_ref(), None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! This module contains the implementation of abstract virtual node.
|
||||
|
||||
use super::{VChild, VComp, VDiff, VList, VTag, VText};
|
||||
use crate::html::{Component, Renderable};
|
||||
use crate::html::{AnyScope, Component, Renderable};
|
||||
use cfg_if::cfg_if;
|
||||
use log::warn;
|
||||
use std::cmp::PartialEq;
|
||||
|
@ -63,15 +63,16 @@ impl VDiff for VNode {
|
|||
|
||||
fn apply(
|
||||
&mut self,
|
||||
scope: &AnyScope,
|
||||
parent: &Element,
|
||||
previous_sibling: Option<&Node>,
|
||||
ancestor: Option<VNode>,
|
||||
) -> Option<Node> {
|
||||
match *self {
|
||||
VNode::VTag(ref mut vtag) => vtag.apply(parent, previous_sibling, ancestor),
|
||||
VNode::VText(ref mut vtext) => vtext.apply(parent, previous_sibling, ancestor),
|
||||
VNode::VComp(ref mut vcomp) => vcomp.apply(parent, previous_sibling, ancestor),
|
||||
VNode::VList(ref mut vlist) => vlist.apply(parent, previous_sibling, ancestor),
|
||||
VNode::VTag(ref mut vtag) => vtag.apply(scope, parent, previous_sibling, ancestor),
|
||||
VNode::VText(ref mut vtext) => vtext.apply(scope, parent, previous_sibling, ancestor),
|
||||
VNode::VComp(ref mut vcomp) => vcomp.apply(scope, parent, previous_sibling, ancestor),
|
||||
VNode::VList(ref mut vlist) => vlist.apply(scope, parent, previous_sibling, ancestor),
|
||||
VNode::VRef(ref mut node) => {
|
||||
let sibling = match ancestor {
|
||||
Some(mut n) => n.detach(parent),
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use super::{
|
||||
Attributes, Classes, Listener, Listeners, Patch, Reform, Transformer, VDiff, VList, VNode,
|
||||
};
|
||||
use crate::html::NodeRef;
|
||||
use crate::html::{AnyScope, NodeRef};
|
||||
use crate::utils::document;
|
||||
use cfg_if::cfg_if;
|
||||
use cfg_match::cfg_match;
|
||||
|
@ -399,6 +399,7 @@ impl VDiff for VTag {
|
|||
/// to compute what to patch in the actual DOM nodes.
|
||||
fn apply(
|
||||
&mut self,
|
||||
scope: &AnyScope,
|
||||
parent: &Element,
|
||||
previous_sibling: Option<&Node>,
|
||||
ancestor: Option<VNode>,
|
||||
|
@ -498,7 +499,7 @@ impl VDiff for VTag {
|
|||
|
||||
// Process children
|
||||
self.children
|
||||
.apply(&element, None, ancestor.map(|a| a.children.into()));
|
||||
.apply(scope, &element, None, ancestor.map(|a| a.children.into()));
|
||||
|
||||
let node = self.reference.as_ref().map(|e| {
|
||||
let node = cfg_match! {
|
||||
|
@ -876,6 +877,7 @@ mod tests {
|
|||
#[cfg(feature = "web_sys")]
|
||||
let document = web_sys::window().unwrap().document().unwrap();
|
||||
|
||||
let scope = AnyScope::default();
|
||||
let div_el = document.create_element("div").unwrap();
|
||||
let namespace = SVG_NAMESPACE;
|
||||
#[cfg(feature = "web_sys")]
|
||||
|
@ -887,17 +889,17 @@ mod tests {
|
|||
let mut svg_node = html! { <svg>{path_node}</svg> };
|
||||
|
||||
let svg_tag = assert_vtag(&mut svg_node);
|
||||
svg_tag.apply(&div_el, None, None);
|
||||
svg_tag.apply(&scope, &div_el, None, None);
|
||||
assert_namespace(svg_tag, SVG_NAMESPACE);
|
||||
let path_tag = assert_vtag(svg_tag.children.get_mut(0).unwrap());
|
||||
assert_namespace(path_tag, SVG_NAMESPACE);
|
||||
|
||||
let g_tag = assert_vtag(&mut g_node);
|
||||
g_tag.apply(&div_el, None, None);
|
||||
g_tag.apply(&scope, &div_el, None, None);
|
||||
assert_namespace(g_tag, HTML_NAMESPACE);
|
||||
g_tag.reference = None;
|
||||
|
||||
g_tag.apply(&svg_el, None, None);
|
||||
g_tag.apply(&scope, &svg_el, None, None);
|
||||
assert_namespace(g_tag, SVG_NAMESPACE);
|
||||
}
|
||||
|
||||
|
@ -1019,6 +1021,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn swap_order_of_classes() {
|
||||
let scope = AnyScope::default();
|
||||
let parent = document().create_element("div").unwrap();
|
||||
|
||||
#[cfg(feature = "std_web")]
|
||||
|
@ -1027,7 +1030,7 @@ mod tests {
|
|||
document().body().unwrap().append_child(&parent).unwrap();
|
||||
|
||||
let mut elem = html! { <div class=("class-1", "class-2", "class-3")></div> };
|
||||
elem.apply(&parent, None, None);
|
||||
elem.apply(&scope, &parent, None, None);
|
||||
|
||||
let vtag = if let VNode::VTag(vtag) = elem {
|
||||
vtag
|
||||
|
@ -1053,7 +1056,7 @@ mod tests {
|
|||
} else {
|
||||
panic!("should be vtag")
|
||||
};
|
||||
vtag.apply(&parent, None, Some(VNode::VTag(ancestor)));
|
||||
vtag.apply(&scope, &parent, None, Some(VNode::VTag(ancestor)));
|
||||
|
||||
let expected = "class-3 class-2 class-1";
|
||||
assert_eq!(vtag.classes.to_string(), expected);
|
||||
|
@ -1069,6 +1072,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn add_class_to_the_middle() {
|
||||
let scope = AnyScope::default();
|
||||
let parent = document().create_element("div").unwrap();
|
||||
|
||||
#[cfg(feature = "std_web")]
|
||||
|
@ -1077,7 +1081,7 @@ mod tests {
|
|||
document().body().unwrap().append_child(&parent).unwrap();
|
||||
|
||||
let mut elem = html! { <div class=("class-1", "class-3")></div> };
|
||||
elem.apply(&parent, None, None);
|
||||
elem.apply(&scope, &parent, None, None);
|
||||
|
||||
let vtag = if let VNode::VTag(vtag) = elem {
|
||||
vtag
|
||||
|
@ -1103,7 +1107,7 @@ mod tests {
|
|||
} else {
|
||||
panic!("should be vtag")
|
||||
};
|
||||
vtag.apply(&parent, None, Some(VNode::VTag(ancestor)));
|
||||
vtag.apply(&scope, &parent, None, Some(VNode::VTag(ancestor)));
|
||||
|
||||
let expected = "class-1 class-2 class-3";
|
||||
assert_eq!(vtag.classes.to_string(), expected);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//! This module contains the implementation of a virtual text node `VText`.
|
||||
|
||||
use super::{Reform, VDiff, VNode};
|
||||
use crate::html::AnyScope;
|
||||
use crate::utils::document;
|
||||
use cfg_if::cfg_if;
|
||||
use cfg_match::cfg_match;
|
||||
|
@ -53,6 +54,7 @@ impl VDiff for VText {
|
|||
/// Renders virtual node over existing `TextNode`, but only if value of text had changed.
|
||||
fn apply(
|
||||
&mut self,
|
||||
_scope: &AnyScope,
|
||||
parent: &Element,
|
||||
previous_sibling: Option<&Node>,
|
||||
ancestor: Option<VNode>,
|
||||
|
|
Loading…
Reference in New Issue