Beispiel #1
0
        /// <summary>
        /// Find the most logic direction to move the cursor so that it matches the where has clicked
        /// </summary>
        /// <param name="Selection"></param>
        /// <returns></returns>
        public static Direction FindSelectionToLogicalPosition(MarkupRange Selection, IHTMLElement body, bool?forward)
        {
            // There is a selection, not just a click
            if (!Selection.Start.IsEqualTo(Selection.End))
            {
                return(Direction.None);
            }

            Direction dir = ImageBreakout(Selection.Start);

            if (dir != Direction.None)
            {
                return(dir);
            }

            MarkupContext contextRight = Selection.Start.Right(false);
            MarkupContext contextLeft  = Selection.Start.Left(false);

            // there is text or some other type of content around the click
            if (!((contextLeft.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope || contextLeft.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope) &&
                  (contextRight.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope || contextRight.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope)))
            {
                return(Direction.None);
            }

            // The click is not between two block elements, so it should be fine where it is
            if (!ElementFilters.IsBlockElement(contextLeft.Element) || !ElementFilters.IsBlockElement(contextRight.Element))
            {
                return(Direction.None);
            }

            // </blockElement>|</postBody>
            if (contextLeft.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope &&
                !IsSmartContent(contextLeft) &&
                contextRight.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope &&
                contextRight.Element.id == body.id)
            {
                return(Direction.Left);
            }

            // <postBody>|<blockElement>
            if (contextRight.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope &&
                !IsSmartContent(contextRight) &&
                contextLeft.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope &&
                contextLeft.Element.id == body.id)
            {
                return(Direction.Right);
            }

            // </blockElement>|<blockElement>
            if (contextLeft.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope &&
                !IsSmartContent(contextLeft) &&
                contextRight.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope &&
                !IsSmartContent(contextRight))
            {
                return(forward == null || forward == true ? Direction.Right : Direction.Left);
            }

            return(Direction.None);
        }
        /// <summary>
        /// Returns true if this range is composes entirely of non-visible elements.
        /// </summary>
        /// <param name="inScopeContextsOnly">flag to ignore out of scope element
        /// (use false unless you absolutely want to ignore visible content in cases like
        ///  [start]&lt;p&gt;[end]&lt;/p&gt;)</param>
        /// <returns></returns>
        public bool IsEmptyOfContent(bool inScopeContextsOnly)
        {
            try
            {
                bool isEmptyOfContent = true;

                WalkRange(
                    delegate(MarkupRange currentRange, MarkupContext context, string text)
                {
                    text = text ?? string.Empty;
                    if (!String.IsNullOrEmpty(text.Trim()))
                    {
                        isEmptyOfContent = false;
                        return(false);
                    }

                    if (context.Element != null && ElementFilters.IsVisibleEmptyElement(context.Element))
                    {
                        isEmptyOfContent = false;
                        return(false);
                    }

                    // Continue walking the range.
                    return(true);
                },
                    inScopeContextsOnly);

                return(isEmptyOfContent);
            }
            catch (Exception)
            {
                return(false);
            }
        }
        public static MarkupRange GetEditableRange(IHTMLElement e, MshtmlMarkupServices markupServices)
        {
            IHTMLElement3 editableElement = null;

            while (e != null)
            {
                if (((IHTMLElement3)e).isContentEditable)
                {
                    editableElement = (IHTMLElement3)e;
                    if (ElementFilters.IsBlockElement(e))
                    {
                        break;
                    }
                }
                else
                {
                    break;
                }
                e = e.parentElement;
            }

            if (editableElement != null)
            {
                return(markupServices.CreateMarkupRange((IHTMLElement)editableElement, false));
            }
            else
            {
                return(null);
            }
        }
Beispiel #4
0
 private static MoveFilterResult StopBeforeExitBlock(MarkupContext mc)
 {
     if (mc.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope && ElementFilters.IsBlockElement(mc.Element))
     {
         return(MoveFilterResult.STOP_BACK);
     }
     return(MoveFilterResult.CONTINUE);
 }
Beispiel #5
0
 private static MoveFilterResult StopAfterEnterBlock(MarkupContext mc)
 {
     if (mc.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope && ElementFilters.IsBlockElement(mc.Element))
     {
         return(MoveFilterResult.STOP);
     }
     return(MoveFilterResult.CONTINUE);
 }
Beispiel #6
0
        /// <summary>
        /// Retrieves the block element that this pointer is positioned within.
        /// </summary>
        public IHTMLElement CurrentBlockScope()
        {
            IHTMLElement parent = CurrentScope;

            while (parent != null && !ElementFilters.IsBlockElement(parent))
            {
                parent = parent.parentElement;
            }
            return(parent);
        }
Beispiel #7
0
 private static MoveFilterResult StopBeforeVisible(MarkupContext mc)
 {
     if (mc.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text)
     {
         return(MoveFilterResult.STOP_BACK);
     }
     if (mc.Element != null && ElementFilters.IsInlineElement(mc.Element) && !ElementFilters.IsVisibleEmptyElement(mc.Element))
     {
         return(MoveFilterResult.CONTINUE);
     }
     return(MoveFilterResult.STOP_BACK);
 }
        public void RemoveElementsByTagId(_ELEMENT_TAG_ID tagId, bool onlyIfNoAttributes)
        {
            if (tagId == _ELEMENT_TAG_ID.TAGID_NULL)
            {
                return;
            }

            // Remove the tagId up the parent chain
            IHTMLElement currentElement = ParentElement();

            while (currentElement != null)
            {
                if (MarkupServices.GetElementTagId(currentElement) == tagId &&
                    (!onlyIfNoAttributes || !HTMLElementHelper.HasMeaningfulAttributes(currentElement)))
                {
                    try
                    {
                        MarkupServices.RemoveElement(currentElement);
                    }
                    catch (COMException e)
                    {
                        Trace.Fail(String.Format("Failed to remove element ({0}) with error: {1}",
                                                 currentElement.outerHTML, // {0}
                                                 e                         // {1}
                                                 ));
                    }
                }
                currentElement = currentElement.parentElement;
            }

            // Remove any other instances
            IHTMLElement[] elements =
                GetElements(ElementFilters.CreateTagIdFilter(MarkupServices.GetNameForTagId(tagId)), false);
            foreach (IHTMLElement e in elements)
            {
                if (MarkupServices.GetElementTagId(e) == tagId &&
                    (!onlyIfNoAttributes || !HTMLElementHelper.HasMeaningfulAttributes(e)))
                {
                    try
                    {
                        MarkupServices.RemoveElement(e);
                    }
                    catch (COMException ex)
                    {
                        Trace.Fail(String.Format("Failed to remove element ({0}) with error: {1}",
                                                 e.outerHTML, // {0}
                                                 ex           // {1}
                                                 ));
                    }
                }
            }
        }
Beispiel #9
0
        public static void SplitBlockForInsertionOrBreakout(MshtmlMarkupServices markupServices, MarkupRange bounds, MarkupPointer insertAt)
        {
            IHTMLElement currentBlock = insertAt.GetParentElement(ElementFilters.BLOCK_OR_TABLE_CELL_ELEMENTS);

            if (currentBlock == null)
            {
                return;
            }

            if (ElementFilters.IsBlockQuoteElement(currentBlock) || ElementFilters.IsTableCellElement(currentBlock))
            {
                return;
            }


            MarkupPointer blockStart = markupServices.CreateMarkupPointer(currentBlock, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
            MarkupPointer blockEnd   = markupServices.CreateMarkupPointer(currentBlock, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);

            if (bounds != null && (blockStart.IsLeftOf(bounds.Start) || blockEnd.IsRightOf(bounds.End)))
            {
                return;
            }

            // Don't split if at the beginning or end of the visible content in the block.
            // Instead just move the insertion point outside the block.
            MarkupRange testRange = markupServices.CreateMarkupRange();

            testRange.Start.MoveToPointer(insertAt);
            testRange.End.MoveAdjacentToElement(currentBlock, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd);
            if (testRange.IsEmptyOfContent())
            {
                insertAt.MoveAdjacentToElement(currentBlock, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
                return;
            }
            testRange.Start.MoveAdjacentToElement(currentBlock, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
            testRange.End.MoveToPointer(insertAt);
            if (testRange.IsEmptyOfContent())
            {
                insertAt.MoveAdjacentToElement(currentBlock, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
                return;
            }

            MarkupPointer moveTarget = markupServices.CreateMarkupPointer(blockEnd);

            markupServices.Move(insertAt, blockEnd, moveTarget);
            insertAt.MoveAdjacentToElement(currentBlock, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
        }
        //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>
        /// Determines if a range has a particular _ELEMENT_TAG_ID applied.
        /// </summary>
        /// <param name="tagId"></param>
        /// <param name="partially">If true, then IsTagId will return true if any part of it is contained within a tagId element.
        ///                         If false, then IsTagId will return true only if the range is entirely contained within a tagId element.</param>
        /// <returns></returns>
        public bool IsTagId(_ELEMENT_TAG_ID tagId, bool partially)
        {
            // This first block of code will return true if the range is entirely contained within an element with the given tagId.
            IHTMLElement currentElement = ParentElement();

            while (currentElement != null)
            {
                if (MarkupServices.GetElementTagId(currentElement) == tagId)
                {
                    return(true);
                }

                currentElement = currentElement.parentElement;
            }

            // This second block of code will return true if the range is partially contained within an element with the given tagId.
            if (partially)
            {
                IHTMLElement[] elements = GetElements(ElementFilters.CreateTagIdFilter(MarkupServices.GetNameForTagId(tagId)), false);
                return(elements.Length > 0);
            }

            return(false);
        }