1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
//! Our Patch enum is intentionally kept in it's own file for easy inclusion into //! The Percy Book. use crate::{VText, VirtualNode}; use std::collections::HashMap; mod apply_patches; pub use apply_patches::patch; /// A Patch encodes an operation that modifies a real DOM element. /// /// To update the real DOM that a user sees you'll want to first diff your /// old virtual dom and new virtual dom. /// /// This diff operation will generate `Vec<Patch>` with zero or more patches that, when /// applied to your real DOM, will make your real DOM look like your new virtual dom. /// /// Each Patch has a u32 node index that helps us identify the real DOM node that it applies to. /// /// Our old virtual dom's nodes are indexed depth first, as shown in this illustration /// (0 being the root node, 1 being it's first child, 2 being it's first child's first child). /// /// ```text /// .─. /// ( 0 ) /// `┬' /// ┌────┴──────┐ /// │ │ /// ▼ ▼ /// .─. .─. /// ( 1 ) ( 4 ) /// `┬' `─' /// ┌────┴───┐ │ /// │ │ ├─────┬─────┐ /// ▼ ▼ │ │ │ /// .─. .─. ▼ ▼ ▼ /// ( 2 ) ( 3 ) .─. .─. .─. /// `─' `─' ( 5 ) ( 6 ) ( 7 ) /// `─' `─' `─' /// ``` /// /// The patching process is tested in a real browser in crates/virtual-dom-rs/tests/diff_patch.rs #[derive(Debug, PartialEq)] pub enum Patch<'a> { /// Append a vector of child nodes to a parent node id. AppendChildren(NodeIdx, Vec<&'a VirtualNode>), /// For a `node_i32`, remove all children besides the first `len` TruncateChildren(NodeIdx, usize), /// Replace a node with another node. This typically happens when a node's tag changes. /// ex: <div> becomes <span> Replace(NodeIdx, &'a VirtualNode), /// Add attributes that the new node has that the old node does not AddAttributes(NodeIdx, HashMap<&'a str, &'a str>), /// Remove attributes that the old node had that the new node doesn't RemoveAttributes(NodeIdx, Vec<&'a str>), /// Change the text of a Text node. ChangeText(NodeIdx, &'a VText), } type NodeIdx = usize; impl<'a> Patch<'a> { /// Every Patch is meant to be applied to a specific node within the DOM. Get the /// index of the DOM node that this patch should apply to. DOM nodes are indexed /// depth first with the root node in the tree having index 0. pub fn node_idx(&self) -> usize { match self { Patch::AppendChildren(node_idx, _) => *node_idx, Patch::TruncateChildren(node_idx, _) => *node_idx, Patch::Replace(node_idx, _) => *node_idx, Patch::AddAttributes(node_idx, _) => *node_idx, Patch::RemoveAttributes(node_idx, _) => *node_idx, Patch::ChangeText(node_idx, _) => *node_idx, } } }