/// <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);
        }
Example #2
0
        /// <summary>
        /// Makes sure that whole (not parts of) lists are included in the source of a paste.
        /// </summary>
        /// <param name="range">The original source range. The range may be modified.</param>
        /// <param name="markupServices">MarkupServices for the range.</param>
        private void ExpandToIncludeLists(MarkupRange range, MshtmlMarkupServices markupServices)
        {
            MarkupPointer      pointer    = markupServices.CreateMarkupPointer();
            IHTMLElementFilter listFilter =
                ElementFilters.CreateCompoundElementFilter(ElementFilters.LIST_ELEMENTS, ElementFilters.LIST_ITEM_ELEMENTS);

            IHTMLElement[] listElements = range.GetElements(listFilter, false);
            foreach (IHTMLElement element in listElements)
            {
                IHTMLElement parentList = element;
                while (parentList != null && !ElementFilters.IsListElement(parentList))
                {
                    parentList = parentList.parentElement;
                }

                if (parentList != null)
                {
                    pointer.MoveAdjacentToElement(parentList, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
                    if (range.Start.IsRightOf(pointer))
                    {
                        range.Start.MoveToPointer(pointer);
                    }

                    pointer.MoveAdjacentToElement(parentList, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
                    if (range.End.IsLeftOf(pointer))
                    {
                        range.End.MoveToPointer(pointer);
                    }
                }
            }
        }
Example #3
0
        /// <summary>
        /// Returns an array of the parent elements that match the specified filter.
        /// </summary>
        /// <param name="filter"></param>
        /// <returns>an array of matching parents (closest parent at index zero)</returns>
        public IHTMLElement[] GetParentElements(IHTMLElementFilter filter)
        {
            ArrayList    list   = null;
            IHTMLElement parent = CurrentScope;

            while (parent != null)
            {
                if (filter(parent))
                {
                    if (list == null)
                    {
                        list = new ArrayList();
                    }
                    list.Add(parent);
                }
                parent = parent.parentElement;
            }
            if (list != null)
            {
                return(HTMLElementHelper.ToElementArray(list));
            }
            else
            {
                return(new IHTMLElement[0]);
            }
        }
        public IHTMLElement ParentElement(IHTMLElementFilter filter)
        {
            IHTMLElement parent = ParentElement();

            while (parent != null && !filter(parent))
            {
                parent = parent.parentElement;
            }
            return(parent);
        }
Example #5
0
        /// <summary>
        /// Returns the closest parent element that matches the specified filter.
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public IHTMLElement GetParentElement(IHTMLElementFilter filter)
        {
            IHTMLElement parent = CurrentScope;

            while (parent != null && !filter(parent))
            {
                parent = parent.parentElement;
            }
            return(parent);
        }
Example #6
0
        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;
                }
            }
        }
Example #7
0
        private void ApplyBlockStyle(_ELEMENT_TAG_ID styleTagId, MarkupRange selection, MarkupRange maximumBounds, MarkupRange postOpSelection)
        {
            Debug.Assert(selection != maximumBounds, "selection and maximumBounds must be distinct objects");
            SelectionPositionPreservationCookie selectionPreservationCookie = null;

            //update the range cling and gravity so it will stick with the re-arranged block content
            selection.Start.PushCling(false);
            selection.Start.PushGravity(_POINTER_GRAVITY.POINTER_GRAVITY_Left);
            selection.End.PushCling(false);
            selection.End.PushGravity(_POINTER_GRAVITY.POINTER_GRAVITY_Right);

            try
            {
                if (selection.IsEmpty())
                {
                    //nothing is selected, so expand the selection to cover the entire parent block element
                    IHTMLElementFilter stopFilter =
                        ElementFilters.CreateCompoundElementFilter(ElementFilters.BLOCK_ELEMENTS,
                                                                   new IHTMLElementFilter(IsSplitStopElement));
                    MovePointerLeftUntilRegionBreak(selection.Start, stopFilter, maximumBounds.Start);
                    MovePointerRightUntilRegionBreak(selection.End, stopFilter, maximumBounds.End);
                }

                using (IUndoUnit undo = _editor.CreateSelectionUndoUnit(selection))
                {
                    selectionPreservationCookie = SelectionPositionPreservationHelper.Save(_markupServices, postOpSelection, selection);
                    if (selection.IsEmptyOfContent())
                    {
                        ApplyBlockFormatToEmptySelection(selection, styleTagId, maximumBounds);
                    }
                    else
                    {
                        ApplyBlockFormatToContentSelection(selection, styleTagId, maximumBounds);
                    }
                    undo.Commit();
                }
            }
            finally
            {
                selection.Start.PopCling();
                selection.Start.PopGravity();
                selection.End.PopCling();
                selection.End.PopGravity();
            }

            if (!SelectionPositionPreservationHelper.Restore(selectionPreservationCookie, selection, selection.Clone()))
            {
                selection.ToTextRange().select();
            }
        }
Example #8
0
        private void ApplyBlockFormatToEmptySelection(MarkupRange selection, _ELEMENT_TAG_ID styleTagId, MarkupRange maximumBounds)
        {
            bool deleteParentBlock = false;

            //expand the selection to include the parent content block.  If the expansion can cover the block element
            //without exceeding the maximum bounds, then delete the parent element and wrap the selection in the
            //new block element. If the maximum bounds are exceeded, then just wrap the selection around the bounds.
            IHTMLElementFilter stopFilter =
                ElementFilters.CreateCompoundElementFilter(ElementFilters.BLOCK_ELEMENTS,
                                                           new IHTMLElementFilter(IsSplitStopElement));

            MovePointerLeftUntilRegionBreak(selection.Start, stopFilter, maximumBounds.Start);
            MovePointerRightUntilRegionBreak(selection.End, stopFilter, maximumBounds.End);

            MarkupRange tmpRange = selection.Clone();

            tmpRange.End.MoveToPointer(selection.Start);
            IHTMLElement startStopParent = tmpRange.End.GetParentElement(stopFilter);

            if (startStopParent != null)
            {
                tmpRange.Start.MoveAdjacentToElement(startStopParent, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
                if (tmpRange.IsEmptyOfContent()) //the range from the selection the the block start is empty
                {
                    tmpRange.Start.MoveToPointer(selection.End);
                    IHTMLElement endStopParent = tmpRange.Start.GetParentElement(stopFilter);
                    if (endStopParent != null && startStopParent.sourceIndex == endStopParent.sourceIndex)
                    {
                        tmpRange.Start.MoveAdjacentToElement(endStopParent, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd);
                        if (tmpRange.IsEmptyOfContent()) //the range from the selection the the block end is empty
                        {
                            tmpRange.MoveToElement(endStopParent, true);
                            if (maximumBounds.InRange(tmpRange) && !(endStopParent is IHTMLTableCell))
                            {
                                deleteParentBlock = true; //the parent has no useful content outside the selection, so it's safe to delete
                            }
                        }
                    }
                }
            }

            //delete the block parent (if appropriate) and wrap the selection in the new block element.
            if (deleteParentBlock)
            {
                (startStopParent as IHTMLDOMNode).removeNode(false);
            }
            IHTMLElement newBlock = WrapRangeInBlockElement(selection, styleTagId);

            selection.MoveToElement(newBlock, false);
        }
Example #9
0
        /*private void DumpBreakRegions(params ElementBreakRegion[] breakRegions)
         * {
         *  foreach(ElementBreakRegion breakRegion in breakRegions)
         *  {
         *      String elementStartName = breakRegion.BreakStartElement != null ? breakRegion.BreakStartElement.tagName : "";
         *      String elementEndName = breakRegion.BreakEndElement != null ? breakRegion.BreakEndElement.tagName : "";
         *      String breakContent = breakRegion.ContentRange.Text;
         *      if(breakContent != null)
         *          breakContent = breakContent.Replace('\r', ' ').Replace('\n', ' ');
         *      else
         *          breakContent = "";
         *      Trace.WriteLine(String.Format("<{0}>{1}<{2}>", elementStartName, breakContent, elementEndName));
         *  }
         * }*/

        /// <summary>
        /// Splits the specified range into regions based on a region break filter.
        /// </summary>
        /// <param name="range"></param>
        /// <returns></returns>
        private ElementBreakRegion[] SplitIntoElementRegions(MarkupRange range, IHTMLElementFilter regionBreakFilter)
        {
            ArrayList   regions    = new ArrayList();
            MarkupRange blockRange = _markupServices.CreateMarkupRange();

            blockRange.Start.MoveToPointer(range.Start);
            blockRange.End.MoveToPointer(range.Start);
            MarkupContext moveContext = new MarkupContext();

            ElementBreakRegion currentRegion = new ElementBreakRegion(blockRange, null, null);

            while (currentRegion.ContentRange.End.IsLeftOf(range.End))
            {
                if (moveContext.Element != null)
                {
                    if (regionBreakFilter(moveContext.Element))
                    {
                        //move the end of the region back before the break element to close this region
                        currentRegion.ContentRange.End.Left(true);

                        //save the closed region and start the next region
                        currentRegion.BreakEndElement = moveContext.Element;
                        regions.Add(currentRegion);
                        currentRegion = new ElementBreakRegion(currentRegion.ContentRange.Clone(), moveContext.Element, null);
                        currentRegion.ContentRange.Start.MoveToPointer(currentRegion.ContentRange.End);

                        //move the region start over the break element
                        currentRegion.ContentRange.Start.Right(true, moveContext);
                        currentRegion.ContentRange.End.MoveToPointer(currentRegion.ContentRange.Start);
                    }
                }
                currentRegion.ContentRange.End.Right(true, moveContext);
            }

            //save the last break region
            if (moveContext.Element != null && regionBreakFilter(moveContext.Element))
            {
                //move the end of the region back before the break element to close this region
                currentRegion.ContentRange.End.Left(true);
            }
            if (currentRegion.ContentRange.End.IsRightOf(range.End))
            {
                currentRegion.ContentRange.End.MoveToPointer(range.End);
            }
            regions.Add(currentRegion);

            return((ElementBreakRegion[])regions.ToArray(typeof(ElementBreakRegion)));
        }
        public static void RemoveAttributes(MshtmlMarkupServices markupServices, MarkupRange selection, string[] attributesToRemove)
        {
            IHTMLElementFilter[] filters = new IHTMLElementFilter[attributesToRemove.Length];

            for (int i = 0; i < attributesToRemove.Length; i++)
            {
                filters[i] = ElementFilters.CreateElementAttributeFilter(attributesToRemove[i]);
            }

            IHTMLElement[] elements = selection.GetElements(ElementFilters.CreateCompoundElementFilter(filters), false);
            foreach (IHTMLElement element in elements)
            {
                foreach (string attribute in attributesToRemove)
                {
                    element.removeAttribute(attribute, 0);
                }
            }
        }
        //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));
        }
Example #12
0
        public IHTMLElement SeekElementRight(IHTMLElementFilter filter, MarkupPointer boundaryPointer)
        {
            // initialize markup context used to track seeking
            MarkupContext markupContext = new MarkupContext();

            markupContext.Context = _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope;

            while ((boundaryPointer == null || IsLeftOf(boundaryPointer)) &&                          // apply boundary if one exists
                   (markupContext.Context != _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_None))                 // otherwise use end of document
            {
                Right(true, markupContext);

                IHTMLElement element = markupContext.Element;

                if (element != null && filter(element))
                {
                    return(element);
                }
            }

            // none found
            return(null);
        }
        /// <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));
        }
        /// <summary>
        /// Returns true if the provided element is a lt;br&gt; element.
        /// </summary>
        /// <param name="element">The element to examine.</param>
        /// <returns>true if the provided element is a lt;br&gt; element and false otherwise.</returns>
        private bool IsBrElement(IHTMLElement element)
        {
            if (isBrElement == null)
            {
                isBrElement = ElementFilters.CreateElementNameFilter(this.sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_BR));
            }

            return isBrElement(element);
        }
        public static void ChangeElementTagIds(MshtmlMarkupServices markupServices, MarkupRange selection, _ELEMENT_TAG_ID[] tagBefore, _ELEMENT_TAG_ID tagAfter)
        {
            HtmlStyleHelper htmlStyleHelper = new HtmlStyleHelper(markupServices);

            int parentStartDiff = 0;
            MarkupRange rangeToChange;
            bool selectionStartedEmpty = selection.IsEmpty();
            if (selectionStartedEmpty)
            {
                // Operate on parent block element
                rangeToChange = markupServices.CreateMarkupRange(selection.ParentBlockElement());
                parentStartDiff = selection.Start.MarkupPosition - rangeToChange.Start.MarkupPosition;
            }
            else
            {
                rangeToChange = selection;

                // If expanding the selection would not include any new text, then expand it.
                // <h1>|abc|</h1> --> |<h1>abc</h1>|
                rangeToChange.MoveOutwardIfNoText();
            }

            IHTMLElementFilter[] filters = new IHTMLElementFilter[tagBefore.Length];

            for (int i = 0; i < tagBefore.Length; i++)
                filters[i] = ElementFilters.CreateTagIdFilter(markupServices.GetNameForTagId(tagBefore[i]));

            IHTMLElement[] elements = rangeToChange.GetElements(ElementFilters.CreateCompoundElementFilter(filters), false);
            foreach (IHTMLElement element in elements)
            {
                MarkupRange elementRange = markupServices.CreateMarkupRange(element);

                int startPositionDiff = rangeToChange.Start.MarkupPosition - elementRange.Start.MarkupPosition;
                int endPositionDiff = rangeToChange.End.MarkupPosition - elementRange.End.MarkupPosition;

                // @RIBBON TODO: Appropriately preserve element attributes when changing tag ids?
                MarkupRange newElementRange = markupServices.CreateMarkupRange(htmlStyleHelper.WrapRangeInSpanElement(tagAfter, null, elementRange));
                markupServices.RemoveElement(element);

                MarkupPointer startPointer = rangeToChange.Start.Clone();
                startPointer.MoveToMarkupPosition(startPointer.Container, newElementRange.Start.MarkupPosition + startPositionDiff);
                if (startPointer.IsLeftOf(rangeToChange.Start))
                    rangeToChange.Start.MoveToPointer(startPointer);

                MarkupPointer endPointer = rangeToChange.End.Clone();
                endPointer.MoveToMarkupPosition(endPointer.Container, newElementRange.End.MarkupPosition + endPositionDiff);
                if (endPointer.IsLeftOf(elementRange.End))
                    rangeToChange.End.MoveToPointer(endPointer);
            }

            if (selectionStartedEmpty)
            {
                selection.Start.MoveToMarkupPosition(selection.Start.Container, rangeToChange.Start.MarkupPosition + parentStartDiff);
                selection.Collapse(true);
            }
        }
 /// <summary>
 /// Returns the HTML Elements that a direct children of this range.
 /// Note: Only children that are completely contained in this range will be returned.
 /// </summary>
 /// <returns></returns>
 public IHTMLElement[] GetTopLevelElements(IHTMLElementFilter filter)
 {
     return(GetTopLevelBlocksAndCells(filter, false));
 }
        private bool SupportsAlignmentAttribute(IHTMLElement element)
        {
            if (supportsAlignmentAttribute == null)
            {
                // Per the HTML 4.01 and XHTML Transitional DTD, the following elements support the HTML
                // align="LEFT|CENTER|RIGHT|JUSTIFY" attribute.
                supportsAlignmentAttribute = ElementFilters.CreateCompoundElementFilter(
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_DIV)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_P)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_H1)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_H2)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_H3)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_H4)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_H5)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_H6)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_COLGROUP)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_COL)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_THEAD)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TBODY)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TFOOT)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TR)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TH)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TD)));
            }

            return supportsAlignmentAttribute(element);
        }
        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);
        }
 public IHTMLElement ParentElement(IHTMLElementFilter filter)
 {
     IHTMLElement parent = ParentElement();
     while (parent != null && !filter(parent))
     {
         parent = parent.parentElement;
     }
     return parent;
 }
 public CompoundElementFilter(IHTMLElementFilter[] filters)
 {
     _filters = filters;
 }
Example #21
0
 public IHTMLElement SeekElementRight(IHTMLElementFilter filter)
 {
     return(SeekElementRight(filter, null));
 }
 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;
         }
     }
 }
        //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);
        }
 /// <summary>
 /// Returns the HTML Elements that a direct children of this range.
 /// Note: Only children that are completely contained in this range will be returned.
 /// </summary>
 /// <returns></returns>
 public IHTMLElement[] GetTopLevelElements(IHTMLElementFilter filter)
 {
     return GetTopLevelBlocksAndCells(filter, false);
 }
        public static void RemoveAttributes(MshtmlMarkupServices markupServices, MarkupRange selection, string[] attributesToRemove)
        {
            IHTMLElementFilter[] filters = new IHTMLElementFilter[attributesToRemove.Length];

            for (int i = 0; i < attributesToRemove.Length; i++)
                filters[i] = ElementFilters.CreateElementAttributeFilter(attributesToRemove[i]);

            IHTMLElement[] elements = selection.GetElements(ElementFilters.CreateCompoundElementFilter(filters), false);
            foreach (IHTMLElement element in elements)
            {
                foreach (string attribute in attributesToRemove)
                    element.removeAttribute(attribute, 0);
            }
        }
        private bool SupportsPixelHeightAttribute(IHTMLElement element)
        {
            if (this.supportsPixelHeightAttribute == null)
            {
                // Per the HTML 4.01 and XHTML Transitional DTD, the following elements support the HTML height="X"
                // attribute (where X is in pixels).
                this.supportsPixelHeightAttribute = ElementFilters.CreateCompoundElementFilter(
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_IMG)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_APPLET)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_OBJECT)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TH)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TD)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_IFRAME)));
            }

            return this.supportsPixelHeightAttribute(element);
        }
 /// <summary>
 /// Returns the closest parent element that matches the specified filter.
 /// </summary>
 /// <param name="filter"></param>
 /// <returns></returns>
 public IHTMLElement GetParentElement(IHTMLElementFilter filter)
 {
     IHTMLElement parent = CurrentScope;
     while (parent != null && !filter(parent))
     {
         parent = parent.parentElement;
     }
     return parent;
 }
        private bool SupportsPercentageWidthAttribute(IHTMLElement element)
        {
            if (this.supportsPercentageWidthAttribute == null)
            {
                // Per the HTML 4.01 and XHTML Transitional DTD, the following elements support the HTML width="X"
                // attribute (where X is in pixels).
                this.supportsPercentageWidthAttribute = ElementFilters.CreateCompoundElementFilter(
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_IMG)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TABLE)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_COLGROUP)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_COL)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TH)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_TD)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_HR)),
                    ElementFilters.CreateElementNameFilter(sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_IFRAME)));
            }

            return this.supportsPercentageWidthAttribute(element);
        }
 /// <summary>
 /// Returns an array of the parent elements that match the specified filter.
 /// </summary>
 /// <param name="filter"></param>
 /// <returns>an array of matching parents (closest parent at index zero)</returns>
 public IHTMLElement[] GetParentElements(IHTMLElementFilter filter)
 {
     ArrayList list = null;
     IHTMLElement parent = CurrentScope;
     while (parent != null)
     {
         if (filter(parent))
         {
             if (list == null)
                 list = new ArrayList();
             list.Add(parent);
         }
         parent = parent.parentElement;
     }
     if (list != null)
         return HTMLElementHelper.ToElementArray(list);
     else
         return new IHTMLElement[0];
 }
        public static void ChangeElementTagIds(MshtmlMarkupServices markupServices, MarkupRange selection, _ELEMENT_TAG_ID[] tagBefore, _ELEMENT_TAG_ID tagAfter)
        {
            HtmlStyleHelper htmlStyleHelper = new HtmlStyleHelper(markupServices);

            int         parentStartDiff = 0;
            MarkupRange rangeToChange;
            bool        selectionStartedEmpty = selection.IsEmpty();

            if (selectionStartedEmpty)
            {
                // Operate on parent block element
                rangeToChange   = markupServices.CreateMarkupRange(selection.ParentBlockElement());
                parentStartDiff = selection.Start.MarkupPosition - rangeToChange.Start.MarkupPosition;
            }
            else
            {
                rangeToChange = selection;

                // If expanding the selection would not include any new text, then expand it.
                // <h1>|abc|</h1> --> |<h1>abc</h1>|
                rangeToChange.MoveOutwardIfNoText();
            }

            IHTMLElementFilter[] filters = new IHTMLElementFilter[tagBefore.Length];

            for (int i = 0; i < tagBefore.Length; i++)
            {
                filters[i] = ElementFilters.CreateTagIdFilter(markupServices.GetNameForTagId(tagBefore[i]));
            }


            IHTMLElement[] elements = rangeToChange.GetElements(ElementFilters.CreateCompoundElementFilter(filters), false);
            foreach (IHTMLElement element in elements)
            {
                MarkupRange elementRange = markupServices.CreateMarkupRange(element);

                int startPositionDiff = rangeToChange.Start.MarkupPosition - elementRange.Start.MarkupPosition;
                int endPositionDiff   = rangeToChange.End.MarkupPosition - elementRange.End.MarkupPosition;

                // @RIBBON TODO: Appropriately preserve element attributes when changing tag ids?
                MarkupRange newElementRange = markupServices.CreateMarkupRange(htmlStyleHelper.WrapRangeInSpanElement(tagAfter, null, elementRange));
                markupServices.RemoveElement(element);

                MarkupPointer startPointer = rangeToChange.Start.Clone();
                startPointer.MoveToMarkupPosition(startPointer.Container, newElementRange.Start.MarkupPosition + startPositionDiff);
                if (startPointer.IsLeftOf(rangeToChange.Start))
                {
                    rangeToChange.Start.MoveToPointer(startPointer);
                }

                MarkupPointer endPointer = rangeToChange.End.Clone();
                endPointer.MoveToMarkupPosition(endPointer.Container, newElementRange.End.MarkupPosition + endPositionDiff);
                if (endPointer.IsLeftOf(elementRange.End))
                {
                    rangeToChange.End.MoveToPointer(endPointer);
                }
            }

            if (selectionStartedEmpty)
            {
                selection.Start.MoveToMarkupPosition(selection.Start.Container, rangeToChange.Start.MarkupPosition + parentStartDiff);
                selection.Collapse(true);
            }
        }
 public IHTMLElement SeekElementRight(IHTMLElementFilter filter)
 {
     return SeekElementRight(filter, null);
 }
        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;
        }
        public IHTMLElement SeekElementRight(IHTMLElementFilter filter, MarkupPointer boundaryPointer)
        {
            // initialize markup context used to track seeking
            MarkupContext markupContext = new MarkupContext();
            markupContext.Context = _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope;

            while ((boundaryPointer == null || IsLeftOf(boundaryPointer)) &&          // apply boundary if one exists
                (markupContext.Context != _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_None))   // otherwise use end of document
            {
                Right(true, markupContext);

                IHTMLElement element = markupContext.Element;

                if (element != null && filter(element))
                    return element;
            }

            // none found
            return null;
        }
        /// <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);
        }
        /// <summary>
        /// MSHTML does not natively support adding/removing the &lt;s&gt; tag which is the equivalent of the
        /// &lt;strike&gt; tag.
        /// </summary>
        /// <param name="element">The element to check.</param>
        /// <returns>true if the element is a &lt;s&gt; tag and false otherwise.</returns>
        private bool IsNonSupportedStrikeThroughElement(IHTMLElement element)
        {
            if (isNonSupportedStrikeThroughElement == null)
            {
                isNonSupportedStrikeThroughElement = ElementFilters.CreateElementNameFilter(this.sourceMarkupServices.GetNameForTagId(_ELEMENT_TAG_ID.TAGID_S));
            }

            return isNonSupportedStrikeThroughElement(element);
        }
        /// <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;
        }
        /*private void DumpBreakRegions(params ElementBreakRegion[] breakRegions)
        {
            foreach(ElementBreakRegion breakRegion in breakRegions)
            {
                String elementStartName = breakRegion.BreakStartElement != null ? breakRegion.BreakStartElement.tagName : "";
                String elementEndName = breakRegion.BreakEndElement != null ? breakRegion.BreakEndElement.tagName : "";
                String breakContent = breakRegion.ContentRange.Text;
                if(breakContent != null)
                    breakContent = breakContent.Replace('\r', ' ').Replace('\n', ' ');
                else
                    breakContent = "";
                Trace.WriteLine(String.Format("<{0}>{1}<{2}>", elementStartName, breakContent, elementEndName));
            }
        }*/

        /// <summary>
        /// Splits the specified range into regions based on a region break filter.
        /// </summary>
        /// <param name="range"></param>
        /// <returns></returns>
        private ElementBreakRegion[] SplitIntoElementRegions(MarkupRange range, IHTMLElementFilter regionBreakFilter)
        {
            ArrayList regions = new ArrayList();
            MarkupRange blockRange = _markupServices.CreateMarkupRange();
            blockRange.Start.MoveToPointer(range.Start);
            blockRange.End.MoveToPointer(range.Start);
            MarkupContext moveContext = new MarkupContext();

            ElementBreakRegion currentRegion = new ElementBreakRegion(blockRange, null, null);
            while (currentRegion.ContentRange.End.IsLeftOf(range.End))
            {
                if (moveContext.Element != null)
                {
                    if (regionBreakFilter(moveContext.Element))
                    {
                        //move the end of the region back before the break element to close this region
                        currentRegion.ContentRange.End.Left(true);

                        //save the closed region and start the next region
                        currentRegion.BreakEndElement = moveContext.Element;
                        regions.Add(currentRegion);
                        currentRegion = new ElementBreakRegion(currentRegion.ContentRange.Clone(), moveContext.Element, null);
                        currentRegion.ContentRange.Start.MoveToPointer(currentRegion.ContentRange.End);

                        //move the region start over the break element
                        currentRegion.ContentRange.Start.Right(true, moveContext);
                        currentRegion.ContentRange.End.MoveToPointer(currentRegion.ContentRange.Start);
                    }
                }
                currentRegion.ContentRange.End.Right(true, moveContext);
            }

            //save the last break region
            if (moveContext.Element != null && regionBreakFilter(moveContext.Element))
            {
                //move the end of the region back before the break element to close this region
                currentRegion.ContentRange.End.Left(true);
            }
            if (currentRegion.ContentRange.End.IsRightOf(range.End))
                currentRegion.ContentRange.End.MoveToPointer(range.End);
            regions.Add(currentRegion);

            return (ElementBreakRegion[])regions.ToArray(typeof(ElementBreakRegion));
        }