11//! This module contains the implementation of reactive virtual dom concept.
22
3+ #[ doc( hidden) ]
4+ pub mod key;
35#[ doc( hidden) ]
46pub mod vcomp;
57#[ doc( hidden) ]
@@ -14,19 +16,27 @@ pub mod vtext;
1416use crate :: html:: AnyScope ;
1517use cfg_if:: cfg_if;
1618use indexmap:: set:: IndexSet ;
17- use std:: collections:: HashMap ;
1819use std:: fmt;
1920use std:: rc:: Rc ;
2021cfg_if ! {
2122 if #[ cfg( feature = "std_web" ) ] {
2223 use crate :: html:: EventListener ;
23- use stdweb:: web:: { Element , Node } ;
24+ use stdweb:: web:: { Element , INode , Node } ;
2425 } else if #[ cfg( feature = "web_sys" ) ] {
2526 use gloo:: events:: EventListener ;
2627 use web_sys:: { Element , Node } ;
2728 }
2829}
30+ cfg_if ! {
31+ if #[ cfg( feature = "fast_hasher" ) ] {
32+ type HashMap <K , V > = ahash:: AHashMap <K , V , ahash:: RandomState >;
33+ } else {
34+ use std:: collections:: HashMap ;
35+ }
36+ }
2937
38+ #[ doc( inline) ]
39+ pub use self :: key:: Key ;
3040#[ doc( inline) ]
3141pub use self :: vcomp:: { VChild , VComp } ;
3242#[ doc( inline) ]
@@ -185,53 +195,106 @@ enum Reform {
185195
186196 /// Create a new reference (js Node).
187197 ///
188- /// The optional `Node` is used to insert the
189- /// new node in the correct slot of the parent.
198+ /// The optional `Node` is used to insert the new node in the correct slot
199+ /// of the parent.
190200 ///
191- /// If it does not exist, a `previous_sibling` must be
192- /// specified (see `VDiff::apply()`).
193- Before ( Option < Node > ) ,
201+ /// If it does not exist, the `node_position` will be used (see
202+ /// `VDiff::apply()`).
203+ Replace ( VDiffNodePosition ) ,
194204}
195205
196- // TODO(#938): What about to implement `VDiff` for `Element`?
197- // In makes possible to include ANY element into the tree.
206+ #[ derive( Debug ) ]
207+ pub ( crate ) enum VDiffNodePosition {
208+ FirstChild ,
209+ Before ( Node ) ,
210+ After ( Node ) ,
211+ LastChild ,
212+ }
213+
214+ // TODO(#938): What about implementing `VDiff` for `Element`?
215+ // It would make it possible to include ANY element into the tree.
198216// `Ace` editor embedding for example?
199217
200218/// This trait provides features to update a tree by calculating a difference against another tree.
201219pub ( crate ) trait VDiff {
202- /// Remove itself from parent and return the next sibling.
203- fn detach ( & mut self , parent : & Element ) -> Option < Node > ;
220+ /// Remove self from parent and return the next sibling.
221+ fn detach ( & mut self , parent : & Element ) -> VDiffNodePosition ;
204222
205223 /// Scoped diff apply to other tree.
206224 ///
207- /// Virtual rendering for the node. It uses parent node and existing children (virtual and DOM)
208- /// to check the difference and apply patches to the actual DOM representation.
225+ /// Virtual rendering for the node. It uses parent node and existing
226+ /// children (virtual and DOM) to check the difference and apply patches to
227+ /// the actual DOM representation.
228+ ///
229+ /// TODO: Explain that vnodes must be at their position before apply is called.
209230 ///
210231 /// Parameters:
232+ /// - `parent_scope`: the parent `Scope` used for passing messages to the
233+ /// parent `Component`.
211234 /// - `parent`: the parent node in the DOM.
212- /// - `previous_sibling `: the "previous node" in a list of nodes, used to efficiently
235+ /// - `node_position `: the position relative to `parent` used to efficiently
213236 /// find where to put the node.
214- /// - `ancestor`: the node that this node will be replacing in the DOM.
215- /// This method will _always_ remove the `ancestor` from the `parent`.
216- /// - `parent_scope`: the parent `Scope` used for passing messages to the parent `Component`.
237+ /// - `ancestor`: the node that this node will be replacing in the DOM. This
238+ /// method will _always_ remove the `ancestor` from the `parent`.
239+ ///
240+ /// Returns the newly inserted element, if there is one (empty VList don't have one).
217241 ///
218242 /// ### Internal Behavior Notice:
219243 ///
220- /// Note that these modify the DOM by modifying the reference that _already_ exists
221- /// on the `ancestor`. If `self.reference` exists (which it _shouldn't_) this method
222- /// will panic.
244+ /// Note that these modify the DOM by modifying the reference that _already_
245+ /// exists on the `ancestor`. If `self.reference` exists (which it
246+ /// _shouldn't_) this method will panic.
223247 ///
224- /// The exception to this is obviously `VRef` which simply uses the inner `Node` directly
225- /// (always removes the `Node` that exists).
248+ /// The exception to this is obviously `VRef` which simply uses the inner
249+ /// `Node` directly (always removes the `Node` that exists).
226250 fn apply (
227251 & mut self ,
228- scope : & AnyScope ,
252+ parent_scope : & AnyScope ,
229253 parent : & Element ,
230- previous_sibling : Option < & Node > ,
254+ node_position : VDiffNodePosition , // TODO: merge `node_position` and `ancestor`
231255 ancestor : Option < VNode > ,
232256 ) -> Option < Node > ;
233257}
234258
259+ #[ cfg( feature = "web_sys" ) ]
260+ fn insert_node ( node : & Node , parent : & Element , node_position : & VDiffNodePosition ) -> Node {
261+ match node_position {
262+ VDiffNodePosition :: FirstChild => parent
263+ . insert_before ( & node, parent. first_child ( ) . as_ref ( ) )
264+ . expect ( "failed to insert tag before next sibling" ) ,
265+ VDiffNodePosition :: Before ( next_sibling) => parent
266+ . insert_before ( & node, Some ( next_sibling) )
267+ . expect ( "failed to insert tag before next sibling" ) ,
268+ VDiffNodePosition :: After ( previous_sibling) => parent
269+ . insert_before ( & node, previous_sibling. next_sibling ( ) . as_ref ( ) )
270+ . expect ( "failed to insert tag before next sibling" ) ,
271+ VDiffNodePosition :: LastChild => parent. append_child ( node) . expect ( "failed to append tag" ) ,
272+ }
273+ }
274+
275+ #[ cfg( feature = "std_web" ) ]
276+ fn insert_node ( node : & impl INode , parent : & impl INode , node_position : & VDiffNodePosition ) -> Node {
277+ fn insert_before ( node : & impl INode , parent : & impl INode , reference : Option < & Node > ) {
278+ if let Some ( reference) = reference {
279+ parent
280+ . insert_before ( node, reference)
281+ . expect ( "failed to insert tag before next sibling" ) ;
282+ } else {
283+ parent. append_child ( node) ;
284+ }
285+ }
286+
287+ match node_position {
288+ VDiffNodePosition :: FirstChild => insert_before ( node, parent, parent. first_child ( ) . as_ref ( ) ) ,
289+ VDiffNodePosition :: Before ( next_sibling) => insert_before ( node, parent, Some ( next_sibling) ) ,
290+ VDiffNodePosition :: After ( previous_sibling) => {
291+ insert_before ( node, parent, previous_sibling. next_sibling ( ) . as_ref ( ) )
292+ }
293+ VDiffNodePosition :: LastChild => parent. append_child ( node) ,
294+ }
295+ node. as_node ( ) . clone ( )
296+ }
297+
235298/// Transform properties to the expected type.
236299pub trait Transformer < FROM , TO > {
237300 /// Transforms one type to another.
0 commit comments