/// <summary> /// Returns true if the the range contains an element that matches the filter /// </summary> /// <param name="filter"></param> /// <returns></returns> public bool ContainsElements(IHTMLElementFilter filter) { if (!IsEmpty()) { Hashtable usedElements = new Hashtable(); MarkupPointer p = MarkupServices.CreateMarkupPointer(Start); MarkupContext context = p.Right(false); //move p through the range to locate each the elements adding elements that pass the filter while (p.IsLeftOfOrEqualTo(End)) { if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope) { if (usedElements[context.Element] == null) { if (filter(context.Element)) { return(true); } } //cache the fact that we've already tested this element. usedElements[context.Element] = context.Element; } p.Right(true, context); } } return(false); }
/// <summary> /// Condenses this range into the smallest well-formed state that still contains the same /// text markup. /// </summary> /// <returns></returns> public bool Trim() { MarkupPointer newStart = MarkupServices.CreateMarkupPointer(Start); MarkupPointer newEnd = MarkupServices.CreateMarkupPointer(End); MarkupContext context = new MarkupContext(); //set newStart adjacent to the first text element to its right newStart.Right(true, context); while (!HasContentBetween(Start, newStart) && newStart.IsLeftOf(End)) { newStart.Right(true, context); } if (HasContentBetween(Start, newStart)) { newStart.Left(true); //we overstepped the text, so back up one step } //set newEnd adjacent to the first text element to its left newEnd.Left(true, context); while (!HasContentBetween(newEnd, End) && newEnd.IsRightOf(Start)) { newEnd.Left(true, context); } if (HasContentBetween(newEnd, End)) { newEnd.Right(true); //we overstepped the text, so back up one step } IHTMLElement sharedParent = GetSharedParent(newStart, newEnd); //span the start and end pointers as siblings by finding the parents of start and end //pointers that are direct children of the sharedParent IHTMLElement child = GetOuterMostChildOfParent(newStart, true, sharedParent); if (child != null) { newStart.MoveAdjacentToElement(child, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin); } child = GetOuterMostChildOfParent(newEnd, false, sharedParent); if (child != null) { newEnd.MoveAdjacentToElement(child, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); } if (!HasContentBetween(newStart, Start) && !HasContentBetween(End, newEnd) && !(Start.IsEqualTo(newStart) && End.IsEqualTo(newEnd))) { Start.MoveToPointer(newStart); End.MoveToPointer(newEnd); return(true); } else { //the range didn't change, so return false. return(false); } }
/// <summary> /// Walk through the markup range letting the walker visit each position. /// </summary> /// <param name="walker">the delegate walking navigating the the markup range</param> /// <param name="inScopeElementsOnly">if true, enter/exit notifications about out-of-scope elements will be suppressed.</param> /// <returns></returns> public void WalkRange(MarkupRangeWalker walker, bool inScopeContextsOnly) { MarkupPointer p1 = MarkupServices.CreateMarkupPointer(Start); MarkupPointer p2 = MarkupServices.CreateMarkupPointer(Start); p1.Cling = false; p2.Cling = false; MarkupContext context = new MarkupContext(); bool continueWalking = true; MarkupRange currentRange = null; while (continueWalking && p2.IsLeftOf(End)) { string text = null; bool isInScope = true; p2.Right(true, context); currentRange = new MarkupRange(p1.Clone(), p2.Clone(), MarkupServices); if (inScopeContextsOnly) { if (context.Element != null) { if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope) { p1.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); isInScope = InRange(p1); } else if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope) { p1.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin); isInScope = InRange(p1); } } else if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text) { // It's possible part of the text is out of scope, so only return the in-scope text. if (currentRange.End.IsRightOf(End)) { currentRange.End.MoveToPointer(End); } } } if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text) { text = currentRange.Text; } if (!inScopeContextsOnly || isInScope) { continueWalking = walker(currentRange, context, text); } p1.MoveToPointer(p2); } }
//this is similar to the GetTopLevelElements except will also return table cells if correct filter // is set and recurse is equal to true public IHTMLElement[] GetTopLevelBlocksAndCells(IHTMLElementFilter filter, bool recurse) { ArrayList list = new ArrayList(); Hashtable usedElements = new Hashtable(); MarkupPointer p = MarkupServices.CreateMarkupPointer(Start); MarkupContext context = p.Right(false); //move p through the range to locate each of the top level elements while (p.IsLeftOf(End)) { if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope) { p.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); if (usedElements[context.Element] == null) { if (p.IsLeftOfOrEqualTo(End) && (filter == null || filter(context.Element))) { list.Add(context.Element); } //special case--inside of a table element, want to get out the cells inside else if (recurse && ElementFilters.TABLE_ELEMENTS(context.Element)) { MarkupRange newRange = MarkupServices.CreateMarkupRange(context.Element); newRange.Start.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin); if (newRange.Start.IsLeftOf(Start)) { newRange.Start.MoveToPointer(Start); } if (newRange.End.IsRightOf(End)) { newRange.End.MoveToPointer(End); } //recursively check inside table element for table cells list.AddRange(newRange.GetTopLevelBlocksAndCells(filter, true)); } //cache the fact that we've already tested this element. usedElements[context.Element] = context.Element; } } p.Right(true, context); } return(HTMLElementHelper.ToElementArray(list)); }
private static void MovePointer(MarkupPointer p, MoveDirection d, MarkupContext context) { if (d == MoveDirection.LEFT) { p.Left(true, context); } else { p.Right(true, context); } }
public override bool ShouldMoveDropLocationRight(MarkupPointer dropLocation) { MarkupContext mc = new MarkupContext(); dropLocation.Right(false, mc); if (mc.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope && ElementFilters.IsBlockElement(mc.Element) && !ContentSourceManager.IsSmartContent(mc.Element)) { dropLocation.Left(false, mc); if (mc.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope && ElementFilters.IsBlockElement(mc.Element)) return true; } return false; }
/// <summary> /// Gets the elements in the range that match the filter. /// </summary> /// <param name="filter">the delegate testing each element to determine if it should be added to the list of elements to return</param> /// <param name="inScopeElementsOnly">if true, the only</param> /// <returns></returns> public IHTMLElement[] GetElements(IHTMLElementFilter filter, bool inScopeElementsOnly) { ArrayList list = new ArrayList(); if (!IsEmpty()) { Hashtable usedElements = new Hashtable(); MarkupPointer p = MarkupServices.CreateMarkupPointer(Start); MarkupPointer end = MarkupServices.CreateMarkupPointer(End); MarkupContext context = p.Right(false); //move p through the range to locate each the elements adding elements that pass the filter while (p.IsLeftOfOrEqualTo(end)) { if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope) { if (usedElements[context.Element] == null) { if ((inScopeElementsOnly && isInScope(context.Element)) || !inScopeElementsOnly) { if (filter(context.Element)) { list.Add(context.Element); } } //cache the fact that we've already tested this element. usedElements[context.Element] = context.Element; } } p.Right(true, context); } } return(HTMLElementHelper.ToElementArray(list)); }
private MarkupPointer GetFirstTextPoint(MarkupPointer from, bool forward) { MarkupPointer firstTextPoint = from.Clone(); MarkupContext context = new MarkupContext(); bool keepLooking = true; do { if (forward) { firstTextPoint.Right(false, context); } else { firstTextPoint.Left(false, context); } if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text) { break; } if (forward) { firstTextPoint.Right(true, context); keepLooking = context.Element != null && firstTextPoint.IsLeftOf(End); } else { firstTextPoint.Left(true, context); keepLooking = context.Element != null && firstTextPoint.IsRightOf(Start); } } while (keepLooking); return(firstTextPoint); }
/// <summary> /// Checks if the MarkupPointer is inside of an anchor that only contains /// an image, and if so, moves the pointer to be outside the anchor. /// This prevents cases where hyperlinked images were getting nested inside /// of each other as a result of drag and drop. /// </summary> public static Direction ImageBreakout(MarkupPointer p) { // If inside <a><img></a>, then move to outside IHTMLElement currentScope = p.CurrentScope; if (currentScope is IHTMLAnchorElement) { IHTMLDOMNode anchor = (IHTMLDOMNode)currentScope; if (anchor.hasChildNodes() && anchor.firstChild is IHTMLImgElement && anchor.firstChild.nextSibling == null) { // Figure out if we are positioned before or after the image; this will determine // whether we want to move before or after the anchor return((p.Right(false).Element is IHTMLImgElement) ? Direction.Left : Direction.Right); } } return(Direction.None); }
/// <summary> /// Retrieve the parent of a child element that is closest to an outer parent element. /// </summary> /// <param name="from">the position to move move out from</param> /// <param name="lookRight">if true, look right for the inner child to start from, otherwise look left</param> /// <param name="outerParent">parent element to move out to</param> /// <returns>the direct child of the outerparent that contains the innerChild</returns> IHTMLElement GetOuterMostChildOfParent(MarkupPointer from, bool lookRight, IHTMLElement outerParent) { MarkupContext lookContext = new MarkupContext(); if (lookRight) { from.Right(false, lookContext); } else { from.Left(false, lookContext); } //if there is a new element coming into scope, start the search from there, //otherwise, start from the currentScope. IHTMLElement innerChild; if (lookContext.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope) { innerChild = lookContext.Element; } else { innerChild = from.CurrentScope; } IHTMLElement parent = innerChild; IHTMLElement innerParent = innerChild; while (parent != outerParent && parent != null) { innerParent = parent; parent = parent.parentElement; } Debug.Assert(innerParent != null, "Parent not found"); if (innerParent == outerParent) //occurs when the from pointer is position directly in the parent. { return(null); } return(innerParent); }
private IHTMLElement GetNextElement(MarkupPointer start, MarkupRange boundaries, IHTMLElementFilter filter, bool forward) { start = start.Clone(); MarkupPointer boundary = forward ? boundaries.End : boundaries.Start; MarkupContext moveResult = new MarkupContext(); _MARKUP_CONTEXT_TYPE skipContext = _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope; //advance the pointer if (forward) start.Right(true, moveResult); else start.Left(true, moveResult); while (forward ? start.IsLeftOf(boundary) : start.IsRightOf(boundary)) { if (moveResult.Element != null && moveResult.Context != skipContext && filter(moveResult.Element)) { return moveResult.Element; } //advance the pointer if (forward) start.Right(true, moveResult); else start.Left(true, moveResult); } return null; }
/// <summary> /// Retrieve the parent of a child element that is closest to an outer parent element. /// </summary> /// <param name="from">the position to move move out from</param> /// <param name="lookRight">if true, look right for the inner child to start from, otherwise look left</param> /// <param name="outerParent">parent element to move out to</param> /// <returns>the direct child of the outerparent that contains the innerChild</returns> IHTMLElement GetOuterMostChildOfParent(MarkupPointer from, bool lookRight, IHTMLElement outerParent) { MarkupContext lookContext = new MarkupContext(); if (lookRight) from.Right(false, lookContext); else from.Left(false, lookContext); //if there is a new element coming into scope, start the search from there, //otherwise, start from the currentScope. IHTMLElement innerChild; if (lookContext.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope) innerChild = lookContext.Element; else innerChild = from.CurrentScope; IHTMLElement parent = innerChild; IHTMLElement innerParent = innerChild; while (parent != outerParent && parent != null) { innerParent = parent; parent = parent.parentElement; } Debug.Assert(innerParent != null, "Parent not found"); if (innerParent == outerParent) //occurs when the from pointer is position directly in the parent. { return null; } return innerParent; }
private static void MovePointer(MarkupPointer p, MoveDirection d, MarkupContext context) { if (d == MoveDirection.LEFT) p.Left(true, context); else p.Right(true, context); }
/// <summary> /// Checks if the MarkupPointer is inside of an anchor that only contains /// an image, and if so, moves the pointer to be outside the anchor. /// This prevents cases where hyperlinked images were getting nested inside /// of each other as a result of drag and drop. /// </summary> public static Direction ImageBreakout(MarkupPointer p) { // If inside <a><img></a>, then move to outside IHTMLElement currentScope = p.CurrentScope; if (currentScope is IHTMLAnchorElement) { IHTMLDOMNode anchor = (IHTMLDOMNode)currentScope; if (anchor.hasChildNodes() && anchor.firstChild is IHTMLImgElement && anchor.firstChild.nextSibling == null) { // Figure out if we are positioned before or after the image; this will determine // whether we want to move before or after the anchor return (p.Right(false).Element is IHTMLImgElement) ? Direction.Left : Direction.Right; } } return Direction.None; }
private void MovePointerRightUntilRegionBreak(MarkupPointer p, IHTMLElementFilter regionBreakFilter, MarkupPointer rightBoundary) { MarkupContext moveContext = new MarkupContext(); while (p.IsLeftOf(rightBoundary)) { p.Right(true, moveContext); if (moveContext.Element != null && regionBreakFilter(moveContext.Element)) { p.Left(true); return; } } }