IEnumerable <DomElementEvent> CloseUntilMatch(string name, Fragment closingFragment) { // Find an element to close var close = stack.FirstOrDefault(x => x.IsNamed(name)); if (close != null) { if (stack.Count > 0 && !stack.Peek().IsNamed(name)) { stack.Pop(); yield return(DomElementEvent.Pop(null)); } stack.Pop(); yield return(DomElementEvent.Pop(closingFragment)); } }
IEnumerable <DomElementEvent> _Execute(IEnumerable <Fragment> fragments) { foreach (var fragment in fragments) { switch (fragment.FragmentType) { case FragmentType.Comment: case FragmentType.Doctype: case FragmentType.Text: yield return(DomElementEvent.Child(fragment)); break; case FragmentType.Close: if (VoidElements.Contains(fragment.Value.ToLowerInvariant())) { break; } if (stack.Any(x => x.IsNamed(fragment.Value))) { foreach (var close in CloseUntilMatch(fragment.Value, fragment)) { yield return(close); } } else { // If there's nothing to close, this is invalid HTML, push through // as a child of the current node, but do not pop the stack. yield return(new DomElementEvent(fragment, DomElementEventType.Child)); } break; case FragmentType.Open: var nameLower = fragment.Value.ToLowerInvariant(); if (ParagraphClosingTags.Contains(nameLower)) { foreach (var pClose in CloseUntilMatch("p", null)) { yield return(pClose); } } else if (nameLower == "li") { // Find the first UL or LI. var parentLiOrUl = stack.FirstOrDefault(x => x.IsNamed("li") || x.IsNamed("ul")); // If something is found and it's an LI, then we can close it. // (Note: checking for ULs so we don't close an LI from a grand-parent UL) if (parentLiOrUl?.IsNamed("li") == true) { foreach (var liClose in CloseUntilMatch("li", parentLiOrUl.AsCloseFragment())) { yield return(liClose); } } } bool shouldPush = !fragment.IsSelfClosing && !VoidElements.Contains(fragment.Value.ToLowerInvariant()); var eventType = shouldPush ? DomElementEventType.Push : DomElementEventType.Child; yield return(new DomElementEvent(fragment, eventType)); if (shouldPush) { stack.Push(fragment); } break; } } while (stack.Count > 0) { stack.Pop(); yield return(DomElementEvent.Pop(null)); } }