Example #1
0
        private static void MoveUnitBounded(MarkupPointer p, MoveDirection direction, MoveContextFilter continueFilter, MarkupPointer boundary)
        {
            MarkupPointer    p1 = p.Clone();
            MarkupPointer    lastGoodPosition = p.Clone();
            MarkupContext    context          = new MarkupContext();
            MoveFilterResult result           = MoveFilterResult.CONTINUE;

            while (CheckMoveBoundary(p1, boundary, direction) && result == MoveFilterResult.CONTINUE)
            {
                lastGoodPosition.MoveToPointer(p1);
                MovePointer(p1, direction, context);
                result = continueFilter(context);
            }
            if (result == MoveFilterResult.CONTINUE)
            {
                //we hit the boundary, so position pointer at the boundary
                p1.MoveToPointer(boundary);
            }
            else if (result == MoveFilterResult.STOP_BACK)
            {
                p1.MoveToPointer(lastGoodPosition);
            }

            p.MoveToPointer(p1);
        }
Example #2
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);
        }
Example #3
0
        /// <summary>
        /// Inspects the content of the container to the left of the markup pointer and optionally moves
        /// the pointer one position to the left.
        /// </summary>
        /// <param name="move">TRUE if the pointer is to move past the content to the left, or FALSE otherwise.
        /// If TRUE, the pointer will move either to the other side of the tag or text to its left, depending on
        /// the CONTEXT_TYPE to the pointer's left.
        /// </param>
        /// <returns>A MarkupContext object describing the content positioned to the pointer's left</returns>
        public MarkupContext Left(bool move)
        {
            MarkupContext context = new MarkupContext();

            Left(move, context);
            return(context);
        }
        /// <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 #5
0
        /// <summary>
        /// Inspects the content of the container to the right of the markup pointer and optionally moves
        /// the pointer one position to the right.
        /// </summary>
        /// <param name="move">TRUE if the pointer is to move past the content to the right, or FALSE otherwise.
        /// If TRUE, the pointer will move either to the other side of the tag or text to its right, depending on
        /// the CONTEXT_TYPE to the pointer's right.
        /// </summary>
        /// <param name="move"></param>
        /// <returns>A MarkupContext object describing the content positioned to the pointer's left</returns>
        public MarkupContext Right(bool move)
        {
            MarkupContext context = new MarkupContext();

            Right(move, context);
            return(context);
        }
Example #6
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);
 }
Example #7
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);
 }
Example #8
0
 private static MoveFilterResult StopBeforeEnterScope(MarkupContext mc)
 {
     if (mc.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope)
     {
         return(MoveFilterResult.STOP_BACK);
     }
     return(MoveFilterResult.CONTINUE);
 }
        /// <summary>
        /// Walk through the markup range in reverse, 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 WalkRangeReverse(MarkupRangeWalker walker, bool inScopeContextsOnly)
        {
            MarkupPointer p1 = MarkupServices.CreateMarkupPointer(End);
            MarkupPointer p2 = MarkupServices.CreateMarkupPointer(End);

            p1.Cling = false;
            p2.Cling = false;
            MarkupContext context         = new MarkupContext();
            bool          continueWalking = true;
            MarkupRange   currentRange    = null;

            while (continueWalking && p2.IsRightOf(Start))
            {
                string text      = null;
                bool   isInScope = true;

                p2.Left(true, context);
                currentRange = new MarkupRange(p2.Clone(), p1.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.Start.IsLeftOf(Start))
                        {
                            currentRange.Start.MoveToPointer(Start);
                        }
                    }
                }

                if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text)
                {
                    text = currentRange.Text;
                }

                if (!inScopeContextsOnly || isInScope)
                {
                    continueWalking = walker(currentRange, context, text);
                }

                p1.MoveToPointer(p2);
            }
        }
        /// <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);
            }
        }
Example #11
0
 private static void MovePointer(MarkupPointer p, MoveDirection d, MarkupContext context)
 {
     if (d == MoveDirection.LEFT)
     {
         p.Left(true, context);
     }
     else
     {
         p.Right(true, context);
     }
 }
Example #12
0
 public MoveFilterResult MergeContextFilters(MarkupContext mc)
 {
     foreach (MoveContextFilter filter in _filters)
     {
         MoveFilterResult result = filter(mc);
         if (result != MoveFilterResult.CONTINUE)
         {
             return(result);
         }
     }
     return(MoveFilterResult.CONTINUE);
 }
 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;
 }
Example #14
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);
 }
        private static void PrintHtml(HtmlWriter writer, MshtmlMarkupServices MarkupServices, MarkupRange bounds)
        {
            //create a range to span a single position while walking the doc
            MarkupRange range = MarkupServices.CreateMarkupRange();
            range.Start.MoveToPointer(bounds.Start);
            range.End.MoveToPointer(bounds.Start);

            //create a context that can be reused while walking the document.
            MarkupContext context = new MarkupContext();

            //move the range.End to the right and print out each element along the way
            range.End.Right(true, context);
            while (context.Context != _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_None && range.Start.IsLeftOf(bounds.End))
            {
                string text = null;
                if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text)
                {
                    //if this is a text context, then get the text that is between the start and end points.
                    text = range.HtmlText;

                    //the range.HtmlText operation sometimes returns the outer tags for a text node,
                    //so we need to strip the tags.
                    //FIXME: if the Right/Left operations returned the available text value, this wouldn't be necessary.
                    if (text != null)
                        text = StripSurroundingTags(text);
                }
                else if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope)
                {
                    string htmlText = range.HtmlText;
                    if (context.Element.innerHTML == null && htmlText != null && htmlText.IndexOf("&nbsp;") != -1)
                    {
                        //HACK: Under these conditions, there was a was an invisible NBSP char in the
                        //document that is not detectable by walking through the document with MarkupServices.
                        //So, we force the text of the element to be the &nbsp; char to ensure that the
                        //whitespace that was visible in the editor is visible in the final document.
                        text = "&nbsp;";
                    }
                }

                //print the context.
                printContext(writer, context, text, range);

                //move the start element to the spot where the end currently is so tht there is
                //only ever a single difference in position
                range.Start.MoveToPointer(range.End);

                //move the end to the next position
                range.End.Right(true, context);
            }
        }
        //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>
        /// 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);
        }
Example #18
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));
        }
        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);
        }
        private static void MoveUnitBounded(MarkupPointer p, MoveDirection direction, MoveContextFilter continueFilter, MarkupPointer boundary)
        {
            MarkupPointer p1 = p.Clone();
            MarkupPointer lastGoodPosition = p.Clone();
            MarkupContext context = new MarkupContext();
            MoveFilterResult result = MoveFilterResult.CONTINUE;
            while (CheckMoveBoundary(p1, boundary, direction) && result == MoveFilterResult.CONTINUE)
            {
                lastGoodPosition.MoveToPointer(p1);
                MovePointer(p1, direction, context);
                result = continueFilter(context);
            }
            if (result == MoveFilterResult.CONTINUE)
            {
                //we hit the boundary, so position pointer at the boundary
                p1.MoveToPointer(boundary);
            }
            else if (result == MoveFilterResult.STOP_BACK)
            {
                p1.MoveToPointer(lastGoodPosition);
            }

            p.MoveToPointer(p1);
        }
Example #22
0
        /// <summary>
        /// Appends a description of a MarkupContext context.
        /// </summary>
        /// <param name="e"></param>
        /// <param name="sb"></param>
        private void AppendContextDetail(MarkupContext context, StringBuilder detail, bool isRightContext)
        {
            switch (context.Context)
            {
            case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope:
                if (isRightContext)
                {
                    AppendStartTagString(context.Element, detail);
                }
                else
                {
                    AppendEndTagString(context.Element, detail);
                }
                break;

            case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope:
                if (isRightContext)
                {
                    AppendEndTagString(context.Element, detail);
                }
                else
                {
                    AppendStartTagString(context.Element, detail);
                }
                break;

            case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope:
                AppendEndTagString(context.Element, detail);
                break;

            case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text:
                //not supported for now
                detail.Append("...text...");
                break;
            }
        }
 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;
 }
Example #24
0
 /// <summary>
 /// Inspects the content of the container to the right of the markup pointer and optionally moves
 /// the pointer one position to the right.
 /// </summary>
 /// <param name="move">TRUE if the pointer is to move past the content to the right, or FALSE otherwise.
 /// If TRUE, the pointer will move either to the other side of the tag or text to its right, depending on
 /// the CONTEXT_TYPE to the pointer's right.
 /// </summary>
 /// <param name="move"></param>
 /// <param name="context">context object to populate with the context information</param>
 public void Right(bool move, MarkupContext context)
 {
     PointerRaw.Right(move, out context.Context, out context.Element, IntPtr.Zero, IntPtr.Zero);
 }
 private static MoveFilterResult StopBeforeEnterScope(MarkupContext mc)
 {
     if (mc.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope)
         return MoveFilterResult.STOP_BACK;
     return MoveFilterResult.CONTINUE;
 }
        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;
        }
 private static void MovePointer(MarkupPointer p, MoveDirection d, MarkupContext context)
 {
     if (d == MoveDirection.LEFT)
         p.Left(true, context);
     else
         p.Right(true, context);
 }
 public MoveFilterResult MergeContextFilters(MarkupContext mc)
 {
     foreach (MoveContextFilter filter in _filters)
     {
         MoveFilterResult result = filter(mc);
         if (result != MoveFilterResult.CONTINUE)
             return result;
     }
     return MoveFilterResult.CONTINUE;
 }
        /// <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;
        }
 /// <summary>
 /// Returns true if the current context is an ending tag, assuming the context was retrieved by moving forward.
 /// </summary>
 /// <param name="currentContext">The markup context to examine.</param>
 /// <returns>true if the current context is an ending tag and false otherwise.</returns>
 private bool IsEndTag(MarkupContext currentContext)
 {
     return currentContext.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope;
 }
        /// <summary>
        /// Safely removes the content within this range without leaving the document badly formed.
        /// </summary>
        public void RemoveContent()
        {
            //delete the selection by moving a delete range right (from the start).
            //Each time that a tag that does not entirely exist within this selection
            //is encountered, the range content will be deleted, the deleteRange will
            //skip over the element.
            MarkupRange deleteRange = this.Clone();

            Trace.Assert(deleteRange.Start.Positioned, "Trying to remove content from selection that contains pointers that are not positioned.");

            deleteRange.End.MoveToPointer(deleteRange.Start);
            MarkupPointer p = MarkupServices.CreateMarkupPointer();
            MarkupPointer previousPosition = MarkupServices.CreateMarkupPointer(deleteRange.End);
            MarkupContext context          = new MarkupContext();

            deleteRange.End.Right(true, context);
            while (deleteRange.End.IsLeftOf(End))
            {
                if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope)
                {
                    p.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
                    if (p.IsRightOf(End))
                    {
                        //this element does not exist entirely in this selection, so we need to
                        //ignore it in the delete.

                        //save this position so that the delete range can be repositioned here
                        p.MoveToPointer(deleteRange.End);

                        //move the end left since we overstepped the valid delete range
                        deleteRange.End.MoveToPointer(previousPosition);

                        //delete the content in the deleteRange, and move it back to this position
                        deleteRangeContentAndMoveToPosition(deleteRange, p);
                    }
                    else
                    {
                        //this element exists entirely in this selection, so skip to its end (since
                        //we know it can be deleted)
                        deleteRange.End.MoveToPointer(p);
                    }
                }
                else if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope)
                {
                    p.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
                    if (p.IsLeftOf(Start))
                    {
                        //this element does not exist entirely in this selection, so we need to
                        //ignore it in the delete.

                        //save this position so that the delete range can be repositioned here
                        p.MoveToPointer(deleteRange.End);

                        //move the end left since we overstepped the valid delete range
                        deleteRange.End.MoveToPointer(previousPosition);

                        //delete the content in the deleteRange, and move it back to this position
                        deleteRangeContentAndMoveToPosition(deleteRange, p);
                    }
                    else
                    {
                        //this element exists entirely in this selection, so skip to its end (since
                        //we know it can be deleted)
                        deleteRange.End.MoveToPointer(p);
                    }
                }

                previousPosition.MoveToPointer(deleteRange.End);
                deleteRange.End.Right(true, context);
            }

            //delete the last part of the range
            deleteRange.End.MoveToPointer(End);
            if (!deleteRange.Start.Equals(deleteRange.End))
            {
                MarkupServices.Remove(deleteRange.Start, deleteRange.End);
            }
        }
        /// <summary>
        /// Inspects the range if a new font tag need to be added to apply formatting for the range.
        /// Call this only for ranges that are inside a header element
        /// </summary>
        private void WrapRangeInFontIfNecessary(MarkupRange currentRange, bool turnBold)
        {
            // Check if there is an existing font/span tag that completely wraps this range,
            // we can just use that instead of inserting a new one
            MarkupContext workingContext = new MarkupContext();
            bool wrapFont = true;
            MarkupPointer start = currentRange.Start.Clone();
            start.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Left;
            start.Right(false, workingContext); // Look to the right to see what we have there
            if (workingContext.Element != null && workingContext.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope &&
                IsFontableElement(workingContext.Element))
            {
                start.MoveAdjacentToElement(workingContext.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
                if (currentRange.End.IsEqualTo(start))
                {
                    // There is an existing <FONT>/<SPAN> enclosing the range, no need to wrap again
                    wrapFont = false;

                    // set its font-weight
                    workingContext.Element.style.fontWeight = turnBold ? "bold" : "normal";
                }
            }

            if (wrapFont)
            {
                string weightAttribute = String.Format(CultureInfo.InvariantCulture, "style=\"font-weight: {0}\"", turnBold ? "bold" : "normal");
                HtmlStyleHelper.WrapRangeInElement(markupServices, currentRange, _ELEMENT_TAG_ID.TAGID_FONT, weightAttribute);
            }
        }
 private static MoveFilterResult ContinueFilter(MarkupContext mc)
 {
     return MoveFilterResult.CONTINUE;
 }
 /// <summary>
 /// Inspects the content of the container to the right of the markup pointer and optionally moves
 /// the pointer one position to the right.
 /// </summary>
 /// <param name="move">TRUE if the pointer is to move past the content to the right, or FALSE otherwise.
 /// If TRUE, the pointer will move either to the other side of the tag or text to its right, depending on
 /// the CONTEXT_TYPE to the pointer's right.
 /// </summary>
 /// <param name="move"></param>
 /// <param name="context">context object to populate with the context information</param>
 public void Right(bool move, MarkupContext context)
 {
     PointerRaw.Right(move, out context.Context, out context.Element, IntPtr.Zero, IntPtr.Zero);
 }
 /// <summary>
 /// Inspects the content of the container to the right of the markup pointer and optionally moves
 /// the pointer one position to the right.
 /// </summary>
 /// <param name="move">TRUE if the pointer is to move past the content to the right, or FALSE otherwise.
 /// If TRUE, the pointer will move either to the other side of the tag or text to its right, depending on
 /// the CONTEXT_TYPE to the pointer's right.
 /// </summary>
 /// <param name="move"></param>
 /// <returns>A MarkupContext object describing the content positioned to the pointer's left</returns>
 public MarkupContext Right(bool move)
 {
     MarkupContext context = new MarkupContext();
     Right(move, context);
     return context;
 }
        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>
        /// Walk through the markup range in reverse, 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 WalkRangeReverse(MarkupRangeWalker walker, bool inScopeContextsOnly)
        {
            MarkupPointer p1 = MarkupServices.CreateMarkupPointer(End);
            MarkupPointer p2 = MarkupServices.CreateMarkupPointer(End);
            p1.Cling = false;
            p2.Cling = false;
            MarkupContext context = new MarkupContext();
            bool continueWalking = true;
            MarkupRange currentRange = null;

            while (continueWalking && p2.IsRightOf(Start))
            {
                string text = null;
                bool isInScope = true;

                p2.Left(true, context);
                currentRange = new MarkupRange(p2.Clone(), p1.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.Start.IsLeftOf(Start))
                        {
                            currentRange.Start.MoveToPointer(Start);
                        }
                    }
                }

                if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text)
                {
                    text = currentRange.Text;
                }

                if (!inScopeContextsOnly || isInScope)
                {
                    continueWalking = walker(currentRange, context, text);
                }

                p1.MoveToPointer(p2);
            }
        }
 /// <summary>
 /// Returns true if the current context is an opening tag, assuming the context was retrieved by moving forward.
 /// </summary>
 /// <param name="currentContext">The markup context to examine.</param>
 /// <returns>true if the current context is an opening tag and false otherwise.</returns>
 private bool IsBeginTag(MarkupContext currentContext)
 {
     return currentContext.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope;
 }
        /// <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>
 /// Returns true if the current currentContext is text.
 /// </summary>
 /// <param name="currentContext">The markup currentContext to examine.</param>
 /// <returns>true if the current currentContext is text and false otherwise.</returns>
 private bool IsText(MarkupContext currentContext)
 {
     return currentContext.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text;
 }
        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;
        }
 private static bool IsSmartContent(MarkupContext ctx)
 {
     return ((IHTMLElement3)ctx.Element).contentEditable.ToUpperInvariant() == "FALSE";
 }
        /// <summary>
        /// Safely removes the content within this range without leaving the document badly formed.
        /// </summary>
        public void RemoveContent()
        {
            //delete the selection by moving a delete range right (from the start).
            //Each time that a tag that does not entirely exist within this selection
            //is encountered, the range content will be deleted, the deleteRange will
            //skip over the element.
            MarkupRange deleteRange = this.Clone();

            Trace.Assert(deleteRange.Start.Positioned, "Trying to remove content from selection that contains pointers that are not positioned.");

            deleteRange.End.MoveToPointer(deleteRange.Start);
            MarkupPointer p = MarkupServices.CreateMarkupPointer();
            MarkupPointer previousPosition = MarkupServices.CreateMarkupPointer(deleteRange.End);
            MarkupContext context = new MarkupContext();
            deleteRange.End.Right(true, context);
            while (deleteRange.End.IsLeftOf(End))
            {
                if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope)
                {
                    p.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
                    if (p.IsRightOf(End))
                    {
                        //this element does not exist entirely in this selection, so we need to
                        //ignore it in the delete.

                        //save this position so that the delete range can be repositioned here
                        p.MoveToPointer(deleteRange.End);

                        //move the end left since we overstepped the valid delete range
                        deleteRange.End.MoveToPointer(previousPosition);

                        //delete the content in the deleteRange, and move it back to this position
                        deleteRangeContentAndMoveToPosition(deleteRange, p);
                    }
                    else
                    {
                        //this element exists entirely in this selection, so skip to its end (since
                        //we know it can be deleted)
                        deleteRange.End.MoveToPointer(p);
                    }
                }
                else if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope)
                {
                    p.MoveAdjacentToElement(context.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
                    if (p.IsLeftOf(Start))
                    {
                        //this element does not exist entirely in this selection, so we need to
                        //ignore it in the delete.

                        //save this position so that the delete range can be repositioned here
                        p.MoveToPointer(deleteRange.End);

                        //move the end left since we overstepped the valid delete range
                        deleteRange.End.MoveToPointer(previousPosition);

                        //delete the content in the deleteRange, and move it back to this position
                        deleteRangeContentAndMoveToPosition(deleteRange, p);
                    }
                    else
                    {
                        //this element exists entirely in this selection, so skip to its end (since
                        //we know it can be deleted)
                        deleteRange.End.MoveToPointer(p);
                    }
                }

                previousPosition.MoveToPointer(deleteRange.End);
                deleteRange.End.Right(true, context);
            }

            //delete the last part of the range
            deleteRange.End.MoveToPointer(End);
            if (!deleteRange.Start.Equals(deleteRange.End))
                MarkupServices.Remove(deleteRange.Start, deleteRange.End);
        }
Example #44
0
 private static bool IsSmartContent(MarkupContext ctx)
 {
     return(((IHTMLElement3)ctx.Element).contentEditable.ToUpperInvariant() == "FALSE");
 }
        /// <summary>
        /// Returns the markup pointer to the position of the first exit scope of type tagId or type terminatingTagId which follows this markup range.
        /// Returns null if text exists between the range and such an exit scope, or if there is no such exit scope.
        /// </summary>
        /// <param name="terminatingTagId"></param>
        /// <returns></returns>
        internal MarkupPointer NextExitScopeWithoutInterveningText(MarkupRange selection, _ELEMENT_TAG_ID tagId, _ELEMENT_TAG_ID terminatingTagId, out bool primaryTagIdMatch)
        {
            MarkupContext context = new MarkupContext();

            MarkupPointer pointer = selection.End.Clone();
            primaryTagIdMatch = false;

            while (true)
            {
                pointer.Right(true, context);
                if (context.Element == null)
                    return null;

                switch (context.Context)
                {
                    case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_None:
                        return null;
                    case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope:
                        {
                            if (_markupServices.GetElementTagId(context.Element) == tagId)
                            {
                                primaryTagIdMatch = true;
                                return pointer;
                            }

                            if (terminatingTagId != _ELEMENT_TAG_ID.TAGID_NULL && terminatingTagId == _markupServices.GetElementTagId(context.Element))
                            {
                                return pointer;
                            }
                        }

                        break;
                    case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope:
                    case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope:
                        break;
                    case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text:
                        return null;
                }
            }
        }
        /// <summary>
        /// Returns true if shift+tab focused region changing is supported for the current edit location
        /// </summary>
        /// <returns></returns>
        private bool ShiftTabFocusChangeSupported()
        {
            //Shift-tab is only supported if the caret is positioned at the beginning of the post
            //If the selection is currently inside a non-blockquote block element with no visible content
            //to the left of it, then focus change is supported.

            if (!EditorContext.Selection.SelectedMarkupRange.IsEmpty())
                return false;

            MarkupRange range = ElementRange.Clone();
            range.Start.MoveAdjacentToElement(HTMLElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
            range.End = EditorContext.Selection.SelectedMarkupRange.Start;

            //if there is any text between the caret and the beginning of the post,
            //then ShiftTab focus changing is not allowed.
            string text = range.Text;
            if (text != null && range.Text.Trim() != String.Empty)
                return false;

            MarkupContext context = new MarkupContext();
            range.Start.Right(true, context);
            int blockElementDepth = 0;
            while (range.Start.IsLeftOfOrEqualTo(range.End))
            {
                if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope)
                {
                    string tagName = context.Element.tagName;
                    if (tagName.Equals("BLOCKQUOTE") || ElementFilters.IsListElement(context.Element) || ElementFilters.IsListItemElement(context.Element))
                        return false; //ShiftTab in a blockquote or list implies "un-blockquote" or "un-list"
                    else if (ElementFilters.IsBlockElement(context.Element))
                    {
                        blockElementDepth++;
                        if (blockElementDepth > 1)
                            return false; //there are multiple block elements, so this is not the beginning
                    }
                    else if (ElementFilters.IsVisibleEmptyElement(context.Element))
                        return false; //there is a visible empty element (like an image), so this is not the beginning
                }
                else if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope)
                {
                    if (ElementFilters.IsVisibleEmptyElement(context.Element))
                        return false; //there is a visible empty element (like an image), so this is not the beginning
                }
                range.Start.Right(true, context);
            }

            return true;
        }
        /// <summary>
        /// Hook allowing editor subclasses to override (and veto handlers for) the pre-handle event
        /// </summary>
        /// <param name="inEvtDispId"></param>
        /// <param name="pIEventObj"></param>
        /// <returns></returns>
        protected virtual int OnPreHandleEvent(int inEvtDispId, IHTMLEventObj pIEventObj)
        {
            switch (inEvtDispId)
            {
                case DISPID_HTMLELEMENTEVENTS2.ONMOUSEMOVE:
                    //fix evil bug 435455 - removing invalid selections using the Selection.empty()
                    //call during onSelectionChanged is known to cause the editor to crash during
                    //mouseUp if a dragdrop operation had been started by the editor.  To prevent
                    //the editor from hitting this condition, we hook the mouseMove event and eat
                    //it if the editor's selection state is invalid. This prevents the editor from
                    //intiating a dragdrop while in an invalid selection state.
                    if ((Control.MouseButtons & MouseButtons.Left) == MouseButtons.Left)
                    {
                        if (HasContiguousSelection && !IsValidContiguousSelection())
                        {
                            return HRESULT.S_OK;
                        }
                    }
                    break;
                case DISPID_HTMLELEMENTEVENTS2.ONKEYDOWN:
                    // WinLive 245925: Because we inline some CSS into the font tag (specifically, the font-size
                    // property), we need to make sure that when the user hits enter that the font-size persists
                    // onto the next line. MSHTML does not handle this for us.
                    if (Editable && pIEventObj.keyCode == (int)Keys.Enter && SelectedMarkupRange.IsEmptyOfText(false))
                    {
                        bool restOfBlockElementIsEmpty = true;
                        bool foundFontSizeElement = false;

                        MarkupContext context;
                        MarkupPointer p;
                        for (p = SelectedMarkupRange.Start.Clone(), context = new MarkupContext(); !ElementFilters.IsBlockElement(p.CurrentScope); p.Right(true, context))
                        {
                            if (context.Element != null)
                            {
                                if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope &&
                                    _fontTagWithFontSizeFilter(context.Element))
                                {
                                    // We found the end tag of a font element that wraps our current selection.
                                    foundFontSizeElement = true;
                                }
                                else if (ElementFilters.IsVisibleEmptyElement(context.Element))
                                {
                                    // If there is any content to the right of the cursor in the current block
                                    // element, then it (and any font tags) will go down to the new line
                                    // automatically, so we don't have to worry about anything in this case.
                                    restOfBlockElementIsEmpty = false;
                                    break;
                                }
                            }
                            else if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text)
                            {
                                // If there is any content to the right of the cursor in the current block
                                // element, then it (and any font tags) will go down to the new line
                                // automatically, so we don't have to worry about anything in this case.
                                restOfBlockElementIsEmpty = false;
                                break;
                            }
                        }

                        if (foundFontSizeElement && restOfBlockElementIsEmpty && !ElementFilters.IsHeaderElement(p.CurrentScope))
                        {
                            // Save this for later. It will be processed after the Enter key has been processed.
                            _fontSizeBeforeEnter = GetFontSizeAt(SelectedMarkupRange.Start);
                        }
                    }
                    break;
            }

            return HRESULT.S_FALSE;
        }
 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;
 }
        private MarkupRange ApplyInlineTag(_ELEMENT_TAG_ID tagId, string attributes, MarkupRange selection)
        {
            MarkupRange newSelection = _markupServices.CreateMarkupRange();

            // If the selection is empty, then just insert the tag
            if (selection.IsEmpty())
            {
                newSelection.MoveToElement(WrapRangeInSpanElement(tagId, attributes, selection), false);
                return newSelection;
            }

            // Start at the beginning of the selection move forward until you hit a block start/exit context or the end of the selection

            bool keepApplying = true;
            MarkupContext contextStart = new MarkupContext();
            MarkupRange blockFreeRange = _markupServices.CreateMarkupRange(selection.Start.Clone(), selection.Start.Clone());
            MarkupPointer currentPointer = _markupServices.CreateMarkupPointer(blockFreeRange.Start);

            while (keepApplying)
            {
                // Check if moving right would be beyond the bounds of the selection.
                if (currentPointer.IsRightOfOrEqualTo(selection.End))
                {
                    // We've hit the end of the selection, so we're done.
                    keepApplying = false;
                    Debug.Assert(blockFreeRange.Start.IsLeftOfOrEqualTo(selection.End));
                    blockFreeRange.End.MoveToPointer(selection.End.IsLeftOf(currentPointer) ? selection.End : currentPointer);

                    if (ShouldApplyInlineTagToBlockFreeSelection(blockFreeRange))
                        newSelection.ExpandToInclude(ApplyInlineTagToBlockFreeSelection(tagId, attributes, blockFreeRange));
                    break;
                }

                // Check if the next context is entering or exiting a block.
                currentPointer.Right(false, contextStart);
                if (contextStart.Element != null && ElementFilters.IsBlockElement(contextStart.Element))
                {
                    switch (contextStart.Context)
                    {
                        case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope:

                        case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope:
                            {
                                blockFreeRange.End.MoveToPointer(selection.End.IsLeftOf(currentPointer) ? selection.End : currentPointer);
                                if (ShouldApplyInlineTagToBlockFreeSelection(blockFreeRange))
                                    newSelection.ExpandToInclude(ApplyInlineTagToBlockFreeSelection(tagId, attributes, blockFreeRange));
                                if (contextStart.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope)
                                    blockFreeRange.Start.MoveAdjacentToElement(contextStart.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
                                else if (contextStart.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope)
                                    blockFreeRange.Start.MoveAdjacentToElement(contextStart.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);

                                blockFreeRange.Collapse(true);
                            }
                            break;
                        case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_None:
                            {
                                keepApplying = false;
                                blockFreeRange.End.MoveToPointer(selection.End.IsLeftOf(currentPointer) ? selection.End : currentPointer);
                                if (ShouldApplyInlineTagToBlockFreeSelection(blockFreeRange))
                                    newSelection.ExpandToInclude(ApplyInlineTagToBlockFreeSelection(tagId, attributes, blockFreeRange));
                            }
                            break;
                        default:
                            break;
                    }
                }

                // Finally, move our pointer
                currentPointer.Right(true);
            }

            if (newSelection.Positioned)
                newSelection.Trim();

            return newSelection;
        }
 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;
 }
Example #51
0
 private static MoveFilterResult ContinueFilter(MarkupContext mc)
 {
     return(MoveFilterResult.CONTINUE);
 }
 /// <summary>
 /// Appends a description of a MarkupContext context.
 /// </summary>
 /// <param name="e"></param>
 /// <param name="sb"></param>
 private void AppendContextDetail(MarkupContext context, StringBuilder detail, bool isRightContext)
 {
     switch (context.Context)
     {
         case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope:
             if (isRightContext)
                 AppendStartTagString(context.Element, detail);
             else
                 AppendEndTagString(context.Element, detail);
             break;
         case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope:
             if (isRightContext)
                 AppendEndTagString(context.Element, detail);
             else
                 AppendStartTagString(context.Element, detail);
             break;
         case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope:
             AppendEndTagString(context.Element, detail);
             break;
         case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text:
             //not supported for now
             detail.Append("...text...");
             break;
     }
 }
 /// <summary>
 /// Inspects the content of the container to the left of the markup pointer and optionally moves
 /// the pointer one position to the left.
 /// </summary>
 /// <param name="move">TRUE if the pointer is to move past the content to the left, or FALSE otherwise.
 /// If TRUE, the pointer will move either to the other side of the tag or text to its left, depending on
 /// the CONTEXT_TYPE to the pointer's left.
 /// </param>
 /// <returns>A MarkupContext object describing the content positioned to the pointer's left</returns>
 public MarkupContext Left(bool move)
 {
     MarkupContext context = new MarkupContext();
     Left(move, context);
     return context;
 }