/// <summary>Removes this selector from all the computed styles it affects, except for the target. /// Use ComputedStyle.RemoveMatch(x) instead of calling this directly.</summary> internal void Remove() { for (int i = 0; i < MatchedRoots.Length; i++) { // Remove it (if it's the target and it was active, it'll also remove the style for us too): MatchingRoot root = MatchedRoots[i]; // Remove from matches: ComputedStyle cs = (root.Node as IRenderableNode).ComputedStyle; // Remove the node: if (root.NextInStyle == null) { cs.LastMatch = root.PreviousInStyle; } else { root.NextInStyle.PreviousInStyle = root.PreviousInStyle; } if (root.PreviousInStyle == null) { cs.FirstMatch = root.NextInStyle; } else { root.PreviousInStyle.NextInStyle = root.NextInStyle; } if (root.IsTarget && Active) { // Remove props: cs.MatchChanged(Style, false); } } }
/// <summary>Applies a structurally matched selector to the DOM. /// Occurs shortly after StructureMatch.</summary> public MatchingSelector BakeToTarget(ComputedStyle cs, CssEvent e) { // Get the node: Node node = cs.Element; // First, generate our instance: MatchingSelector ms = new MatchingSelector(); // Update it: ms.Selector = this; ms.MatchedRoots = new MatchingRoot[RootCount]; // For each root, create a MatchingRoot object. // Apply target - this helps track which element we're actually testing: e.CurrentNode = node; e.SelectorTarget = null; // We always start from the tail and work backwards. // If we get a match, then the caller can do whatever it wants to the target. for (int i = RootCount - 1; i >= 0; i--) { // Get the matcher: RootMatcher rm = Roots[i]; // Try matching this root: if (!rm.TryMatch(e.CurrentNode)) { // Failed! If we had a matcher and it has Repeat set true, try again: if (rm.NextMatcher != null && rm.NextMatcher.Repeat) { // Move target: rm.NextMatcher.MoveUpwards(e); // Try matching again: i++; continue; } } else { // Match! e.CurrentNode is the node to add. // Create the instance: MatchingRoot matchedRoot = new MatchingRoot(); matchedRoot.Root = rm; matchedRoot.Selector = ms; matchedRoot.Node = e.CurrentNode; // Get renderable node: IRenderableNode renderable = (e.CurrentNode as IRenderableNode); // Add to selector: ms.MatchedRoots[i] = matchedRoot; // Add: ComputedStyle nodeCs = renderable.ComputedStyle; // Push the match now into the linked list: if (nodeCs.FirstMatch == null) { nodeCs.FirstMatch = matchedRoot; nodeCs.LastMatch = matchedRoot; } else { matchedRoot.PreviousInStyle = nodeCs.LastMatch; nodeCs.LastMatch.NextInStyle = matchedRoot; nodeCs.LastMatch = matchedRoot; } if (rm.IsTarget) { // Update the target now: e.SelectorTarget = renderable.RenderData; } } // If we have a structure matcher, run it now. It'll move CurrentNode for us: if (rm.PreviousMatcher != null) { // Move target: rm.PreviousMatcher.MoveUpwards(e); } } // Final pass - if we have a pseudo-element, apply it now: if (PseudoElement != null) { PseudoElement.Select(e); } // Apply target: ms.Target = e.SelectorTarget; // Finally, refresh all: ms.ResetActive(); return(ms); }