Esempio n. 1
0
        private static void NormalizeBounds(ref MarkupRange bounds)
        {
            bool cloned = false;

            if (bounds.Start.IsRightOf(bounds.End))
            {
                if (!cloned)
                {
                    cloned = true;
                    bounds = bounds.Clone();
                }
                bounds.Normalize();
            }

            MarkupContext ctx = bounds.Start.Right(false);

            while (ctx.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope &&
                   ElementFilters.IsBlockElement(ctx.Element))
            {
                if (!cloned)
                {
                    cloned = true;
                    bounds = bounds.Clone();
                }
                bounds.Start.Right(true);
                bounds.Start.Right(false, ctx);
            }
        }
        /// <summary>
        /// Returns the maximum range that can be safely considered equivalent to this range (without bringing new text into the range).
        /// </summary>
        /// <param name="range"></param>
        /// <returns></returns>
        private MarkupRange CreateMaxSafeRange(MarkupRange range)
        {
            MarkupRange maxRange = range.Clone();

            SelectOuter(maxRange);
            return(maxRange);
        }
        public bool Contains(MarkupRange testRange)
        {
            // Select just the inner-most text to normalize the MarkupRange before comparing it.
            testRange.SelectInner();

            int pos = BinarySearch(words.Keys, testRange.Start.PointerRaw, new MarkupPointerComparer());

            if (pos >= 0)
            {
                if (words.Values[pos].End.IsLeftOf(testRange.End))
                {
                    Debug.Fail("testRange partially overlaps with range");
                    try
                    {
                        Debug.WriteLine("testRange: [" + testRange.Text + "]");
                        Debug.WriteLine("thisRange: [" + words.Values[pos].Text + "]");
                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine(e.ToString());
                    }
                }
                return(true);
            }

            pos = (~pos) - 1;

            if (pos < 0)
            {
                return(false);
            }

            if (words.Values[pos].End.IsRightOf(testRange.Start))
            {
                if (words.Values[pos].End.IsLeftOf(testRange.End))
                {
#if DEBUG
                    MarkupRange temp = testRange.Clone();
                    temp.Start.MoveToPointer(words.Values[pos].End);
                    if ((temp.Text ?? "").Trim().Length > 0)
                    {
                        Debug.Fail("testRange partially overlaps with range");
                        try
                        {
                            Debug.WriteLine("testRange: [" + testRange.Text + "]");
                            Debug.WriteLine("thisRange: [" + words.Values[pos].Text + "]");
                            Debug.WriteLine("overlap:   [" + temp.Text + "]");
                        }
                        catch (Exception e)
                        {
                            Debug.WriteLine(e.ToString());
                        }
                    }
#endif
                }
                return(true);
            }

            return(false);
        }
Esempio n. 4
0
        /// <summary>
        /// Fixes up all the headers in the entire markupRange.
        /// </summary>
        /// <param name="turnBold">Whether or not the text should be turning bold.</param>
        private void FixupHeaders(bool turnBold)
        {
            IHTMLElement elementStartHeader = markupRange.Start.GetParentElement(ElementFilters.HEADER_ELEMENTS);
            IHTMLElement elementEndHeader   = markupRange.End.GetParentElement(ElementFilters.HEADER_ELEMENTS);
            MarkupRange  currentRange       = markupRange.Clone();

            if (elementStartHeader != null)
            {
                // Takes care of the following cases:
                //  <h1>...|blah|...</h1>
                //  <h1>...|blah...</h1>...|...
                MarkupRange startRange = markupServices.CreateMarkupRange(elementStartHeader, false);
                startRange.Start.MoveToPointer(markupRange.Start);

                if (startRange.End.IsRightOf(markupRange.End))
                {
                    startRange.End.MoveToPointer(markupRange.End);
                }

                FixupHeaderRange(startRange, turnBold);

                currentRange.Start.MoveAdjacentToElement(elementStartHeader, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
                if (currentRange.End.IsLeftOf(currentRange.Start))
                {
                    currentRange.End.MoveToPointer(currentRange.Start);
                }
            }

            if (elementEndHeader != null && !HTMLElementHelper.ElementsAreEqual(elementStartHeader, elementEndHeader))
            {
                // Takes care of the following case:
                //  ...|...<h1>...blah|...</h1>
                MarkupRange endRange = markupServices.CreateMarkupRange(elementEndHeader, false);
                endRange.End.MoveToPointer(markupRange.End);

                FixupHeaderRange(endRange, turnBold);

                currentRange.End.MoveAdjacentToElement(elementEndHeader, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
                if (currentRange.Start.IsRightOf(currentRange.End))
                {
                    currentRange.Start.MoveToPointer(currentRange.End);
                }
            }

            if (!markupRange.InRange(currentRange))
            {
                return;
            }

            IHTMLElement[] headerElements = currentRange.GetElements(ElementFilters.HEADER_ELEMENTS, true);
            if (headerElements != null && headerElements.Length > 0)
            {
                foreach (IHTMLElement element in headerElements)
                {
                    MarkupRange headerRange = markupServices.CreateMarkupRange(element, false);
                    FixupHeaderRange(headerRange, turnBold);
                }
            }
        }
        internal void AddDamage(MarkupRange range, bool includeAdjacentWords)
        {
            MarkupRange wordRange = range.Clone();

            _wordHelper.MoveToWordStart(wordRange.Start);
            _wordHelper.MoveToWordEnd(wordRange.End);
            if (includeAdjacentWords)
            {
                ExpandDamageToAdjacentWords(wordRange);
            }
            _AddDamage(wordRange);
        }
Esempio n. 6
0
        private string GetHtmlText(out MarkupPointer blockBoundary)
        {
            MarkupRange  blockRange = _blogPostHtmlEditorControl.SelectedMarkupRange.Clone();
            MarkupRange  textRange  = blockRange.Clone();
            IHTMLElement ele        = blockRange.ParentElement(ElementFilters.IsBlockOrTableCellOrBodyElement);

            if (ele == null)
            {
                blockBoundary = null;
                return(String.Empty);
            }

            blockRange.MoveToElement(ele, false);
            blockBoundary = blockRange.Start;

            //   Fix Bug 616152 - We want the start and end pointer to match so
            //  we can look back from the start of the insertion point (not the end,
            //  which would include the selection that is going to be overwritten)
            textRange.Collapse(true);

            // Fix bug WinLive 59172: Specific characters of mixed characters are broken in mail body after press the 'Enter' key
            // Caused by using MOVEUNIT_PREVCHAR to navigate into Unicode surrogate (32-bit) characters. We work around this by moving
            // only at word or block boundaries.
            string html = null;

            do
            {
                int startPos = textRange.Start.MarkupPosition;
                textRange.Start.MoveUnitBounded(_MOVEUNIT_ACTION.MOVEUNIT_PREVWORDBEGIN, blockBoundary);
                if (textRange.Start.MarkupPosition == startPos)
                {
                    // PREVWORDBEGIN didn't actually move us, due to no word being available.
                    // To avoid an infinite loop, just move the text range to include the whole
                    // block and move on.
                    textRange.Start.MoveToPointer(blockRange.Start);
                    break;
                }

                if (textRange.Positioned && textRange.Start.IsLeftOfOrEqualTo(textRange.End))
                {
                    html = MarkupHelpers.GetRangeTextFast(textRange);
                }

                html = html ?? string.Empty;
            } while (html.Length < MinLookBack && textRange.Start.IsRightOf(blockRange.Start));

            if (html == null && textRange.Positioned && textRange.Start.IsLeftOfOrEqualTo(textRange.End))
            {
                html = MarkupHelpers.GetRangeTextFast(textRange);
            }

            return(html ?? string.Empty);
        }
Esempio n. 7
0
        public TypographicCharacterHandler(MarkupRange currentSelection, InsertHtml insertHtml, IBlogPostImageEditingContext imageEditingContext, IHTMLElement postBodyElement, char c, string htmlText, MarkupPointer blockBoundary)
        {
            _currentSelection = currentSelection.Clone();
            _currentSelection.Start.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Right;
            _currentSelection.End.Gravity   = _POINTER_GRAVITY.POINTER_GRAVITY_Left;
            _insertHtml          = insertHtml;
            _imageEditingContext = imageEditingContext;
            _postBodyElement     = postBodyElement;

            this.c             = c;
            this.htmlText      = htmlText;
            this.blockBoundary = blockBoundary;
        }
Esempio n. 8
0
        private bool IsRangeInUrl(MarkupRange range)
        {
            //must have this range cloned, otherwise in some cases IsInsideURL call
            // was MOVING the current word range! if "www.foo.com" was in the editor,
            // when the final "\"" was the current word, this call MOVED the current
            // word range BACK to www.foo.com, then nextWord would get "\"" and a loop
            // would occur (bug 411528)
            range = range.Clone();
            IMarkupPointer2Raw p2StartRaw = (IMarkupPointer2Raw)range.Start.PointerRaw;
            bool insideUrl;

            p2StartRaw.IsInsideURL(range.End.PointerRaw, out insideUrl);
            return(insideUrl);
        }
Esempio n. 9
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);
        }
Esempio n. 10
0
        private bool ValidateTableSelection(IHTMLTable table, MarkupRange selectionMarkupRange, out bool tableFullySelected)
        {
            // assume table is not fully selected
            tableFullySelected = false;

            // first check to see that this is a "Writer" editable table
            if (!TableHelper.TableElementContainsWriterEditingMark(table as IHTMLElement))
            {
                return(false);
            }

            // get elemental objects we need to analyze the table
            IHTMLElement tableElement     = table as IHTMLElement;
            MarkupRange  tableMarkupRange = selectionMarkupRange.Clone();

            tableMarkupRange.MoveToElement(table as IHTMLElement, true);

            // analyze selection
            bool selectionAtTableStart = tableMarkupRange.Start.IsEqualTo(selectionMarkupRange.Start);
            bool selectionAtTableEnd   = tableMarkupRange.End.IsEqualTo(selectionMarkupRange.End);

            // is the table fully selected?
            if (selectionAtTableStart && selectionAtTableEnd)
            {
                tableFullySelected = true;
                return(true);
            }
            else
            {
                MarkupRange selectionMarkupRange2 = selectionMarkupRange.Clone();
                // is the selection bounded by the table
                IHTMLElement beginParentTable = selectionMarkupRange2.Start.SeekElementLeft(ElementFilters.CreateEqualFilter(tableElement));
                IHTMLElement endParentTable   = selectionMarkupRange2.End.SeekElementRight(ElementFilters.CreateEqualFilter(tableElement));
                return(beginParentTable != null && endParentTable != null);
            }
        }
        private void ExpandDamageToPreviousWord(MarkupRange damageRange)
        {
            MarkupRange previousWordRange = damageRange.Clone();

            previousWordRange.Start.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_PREVWORDBEGIN);

            // If we were already at the first word in the document, moving to the previous word would have put the
            // MarkupPointer outside the body element.
            if (previousWordRange.Start.GetParentElement(ElementFilters.BODY_ELEMENT) != null)
            {
                previousWordRange.Collapse(true);
                previousWordRange.End.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_NEXTWORDEND);
                if (!previousWordRange.IsEmpty() && !_editorControl.IgnoreRangeForSpellChecking(previousWordRange))
                {
                    damageRange.Start.MoveToPointer(previousWordRange.Start);
                }
            }
        }
        public void Add(MarkupRange range)
        {
            MarkupRange newRange = range.Clone();

            newRange.Start.Cling   = false;
            newRange.End.Cling     = false;
            newRange.Start.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Right;
            newRange.End.Gravity   = _POINTER_GRAVITY.POINTER_GRAVITY_Left;

            // Select just the inner-most text so that it is easier to compare to other MarkupRanges.
            newRange.SelectInner();

            try
            {
                words.Add(newRange.Start.PointerRaw, newRange);
            }
            catch (ArgumentException ex)
            {
                Trace.Fail(ex.ToString());
            }
        }
Esempio n. 13
0
        private void SplitBlockForApplyingBlockStyles(MarkupPointer splitPoint, MarkupRange maximumBounds)
        {
            //find the split stop parent
            IHTMLElement splitStop = splitPoint.GetParentElement(new IHTMLElementFilter(IsSplitStopElement));

            if (splitStop != null)
            {
                MarkupPointer stopLocation = _markupServices.CreateMarkupPointer(splitStop, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
                if (maximumBounds.InRange(stopLocation))
                {
                    stopLocation.MoveAdjacentToElement(splitStop, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd);
                    if (maximumBounds.InRange(stopLocation))
                    {
                        maximumBounds = maximumBounds.Clone();
                        maximumBounds.MoveToElement(splitStop, false);
                    }
                }
            }

            MarkupHelpers.SplitBlockForInsertionOrBreakout(_markupServices, maximumBounds, splitPoint);
        }
Esempio n. 14
0
        public void HighlightSpelling(MarkupRange range)
        {
            // check spelling
            MshtmlWordRange wordRange;

            if (range == null) //check the whole document.
            {
                wordRange = new MshtmlWordRange(_htmlDocument, false, _filter, _damageFunction);
            }
            else
            {
                //range is invalid for some reason--damage committed while switching views, getting it later on the timer
                if (!range.Positioned)
                {
                    return;
                }
                else if (range.Text == null || String.IsNullOrEmpty(range.Text.Trim()))
                {
                    //empty range--on a delete for instance, just clear
                    _spellingHighlighter.ClearRange(range.Start, range.End);
                    _ignoredOnce.ClearRange(range);
                    return;
                }
                else
                {
                    MarkupRange origRange = range.Clone();
                    //here are the words to check
                    wordRange = new MshtmlWordRange(_htmlDocument, range, _filter, _damageFunction);
                    //check for emptiness at start and end, clear those
                    _spellingHighlighter.ClearRange(origRange.Start, range.Start);
                    _spellingHighlighter.ClearRange(range.End, origRange.End);

                    _ignoredOnce.ClearRange(range);
                }
            }

            _spellingHighlighter.CheckSpelling(wordRange);
        }
        public FixupSegment(MarkupRange rangeToFixup, TextStyle sourceTextStyle)
        {
            if (rangeToFixup == null)
            {
                throw new ArgumentNullException("rangeToFixup");
            }

            if (!rangeToFixup.Positioned)
            {
                throw new ArgumentException("rangeToFixup must be positioned!");
            }

            if (sourceTextStyle == null)
            {
                throw new ArgumentNullException("sourceTextStyle");
            }

            SourceTextStyle = sourceTextStyle;
            RangeToFixup    = rangeToFixup.Clone();

            // We want the RangeToFixup to stick with the text its wrapped around.
            RangeToFixup.Start.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Right;
            RangeToFixup.End.Gravity   = _POINTER_GRAVITY.POINTER_GRAVITY_Left;
        }
Esempio n. 16
0
 public BoldApplier(MshtmlMarkupServices markupServices, MarkupRange markupRange, IMshtmlCommand boldCommand)
 {
     this.markupServices = markupServices;
     this.markupRange    = markupRange.Clone();
     this.boldCommand    = boldCommand;
 }
Esempio n. 17
0
        /// <summary>
        /// Fixes up a range that is contained in a single header element.
        /// </summary>
        /// <param name="range">A range that is contained in a single header element.</param>
        /// <param name="turnBold">Whether or not the text should be turning bold.</param>
        private void FixupHeaderRange(MarkupRange range, bool turnBold)
        {
            IHTMLElement parentHeaderElement = range.ParentBlockElement();

            if (parentHeaderElement == null || !ElementFilters.IsHeaderElement(parentHeaderElement))
            {
                Debug.Fail("Expected entire range to be inside a single header element.");
                return;
            }

            MarkupRange expandedRange = range.Clone();

            // Make sure we expand the selection to include any <font> tags that may be wrapping us.
            MarkupPointerMoveHelper.MoveUnitBounded(expandedRange.Start, MarkupPointerMoveHelper.MoveDirection.LEFT,
                                                    MarkupPointerAdjacency.BeforeVisible, parentHeaderElement);
            MarkupPointerMoveHelper.MoveUnitBounded(expandedRange.End, MarkupPointerMoveHelper.MoveDirection.RIGHT,
                                                    MarkupPointerAdjacency.BeforeVisible, parentHeaderElement);

            // Walks in-scope elements and clears out any elements or styles that might affect the bold formatting.
            var elementsToRemove = new List <IHTMLElement>();

            expandedRange.WalkRange(
                delegate(MarkupRange currentexpandedRange, MarkupContext context, string text)
            {
                IHTMLElement currentElement = context.Element;
                if (currentElement != null && context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope)
                {
                    if (IsStrongOrBold(currentElement))
                    {
                        elementsToRemove.Add(currentElement);
                    }
                    else if (IsFontableElement(currentElement) && HTMLElementHelper.IsBold((IHTMLElement2)currentElement) != turnBold)
                    {
                        currentElement.style.fontWeight = String.Empty;
                    }
                }

                return(true);
            }, true);

            elementsToRemove.ForEach(e => markupServices.RemoveElement(e));

            // Walks the range to find any segments of text that need to be fixed up.
            var rangesToWrap = new List <MarkupRange>();

            range.WalkRange(
                delegate(MarkupRange currentRange, MarkupContext context, string text)
            {
                if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text)
                {
                    TextStyles currentTextStyles = new TextStyles(currentRange.Start);
                    if (currentTextStyles.Bold != turnBold)
                    {
                        rangesToWrap.Add(currentRange.Clone());
                    }
                }

                return(true);
            }, true);

            rangesToWrap.ForEach(r => WrapRangeInFontIfNecessary(r, turnBold));
        }
        public static MarkupRange ApplyInlineTag(MshtmlMarkupServices markupServices, _ELEMENT_TAG_ID tagId, string attributes, MarkupRange selection, bool toggle)
        {
            HtmlStyleHelper htmlStyleHelper = new HtmlStyleHelper(markupServices);

            // Aligning the with the behavior of Word, we will make <SUP> and <SUB> mutually exclusive.
            // That is, if you are applying <SUB> to a selection that has <SUP> applied already, we will first remove the <SUP>, and vice versa.
            // Wait, if empty and we're on the very end of the already existing formatting, then we just want to jump out and apply...

            MarkupRange selectionToApply = selection.Clone();

            if (toggle)
            {
                // If already entirely inside the tag
                //     If empty and just inside of the closing tag, then jump outside the closing tag
                //     Else remove the tag
                // If already entirely outside the tag
                //     If empty, apply the tag and put selection inside
                //     If non-empty, then apply tag and reselect
                // If partially inside the tag
                //     Remove the tag

                _ELEMENT_TAG_ID mutuallyExclusiveTagId = _ELEMENT_TAG_ID.TAGID_NULL;
                switch (tagId)
                {
                case _ELEMENT_TAG_ID.TAGID_SUP:
                    mutuallyExclusiveTagId = _ELEMENT_TAG_ID.TAGID_SUB;
                    break;

                case _ELEMENT_TAG_ID.TAGID_SUB:
                    mutuallyExclusiveTagId = _ELEMENT_TAG_ID.TAGID_SUP;
                    break;

                default:

                    break;
                }

                if (selection.IsEmpty())
                {
                    // If the selection is empty and we're just inside the tagId closing tag (meaning that there is no text before the closing tag),
                    // then we just hop outside of the tagId closing tag.

                    bool          exitScopeMatchesTagIdToBeApplied;
                    MarkupPointer pointerOutsideTagIdScope = htmlStyleHelper.NextExitScopeWithoutInterveningText(selection,
                                                                                                                 tagId,
                                                                                                                 mutuallyExclusiveTagId,
                                                                                                                 out exitScopeMatchesTagIdToBeApplied);

                    if (pointerOutsideTagIdScope != null)
                    {
                        selectionToApply = markupServices.CreateMarkupRange(pointerOutsideTagIdScope, pointerOutsideTagIdScope);
                        if (exitScopeMatchesTagIdToBeApplied)
                        {
                            return(selectionToApply);
                        }
                        // else we still need to apply tagId
                    }
                }

                // If a mutually exclusive tag is applied, then remove it.
                if (selectionToApply.IsTagId(mutuallyExclusiveTagId, true))
                {
                    selectionToApply.RemoveElementsByTagId(mutuallyExclusiveTagId, false);
                }

                // If this tag is already applied, then remove it and return.
                if (selectionToApply.IsTagId(tagId, true))
                {
                    selectionToApply.RemoveElementsByTagId(tagId, false);
                    return(selectionToApply);
                }
            }

            return(htmlStyleHelper.ApplyInlineTag(tagId, attributes, selectionToApply));
        }
Esempio n. 19
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();
            }
        }
        public void ClearRange(MarkupRange clear)
        {
            if (words.Count == 0)
            {
                return;
            }

            // Just being defensive here
            if (!clear.Positioned)
            {
                return;
            }

            // Debug.WriteLine(string.Format("ClearRange:\r\n{0}\r\n{1}", clear.Start.PositionTextDetail, clear.End.PositionTextDetail));

            /*
             * Start from the first range in the list where the start is left of
             * the Clear range's end. Take a look at each range until you get to
             * one where the range's end is left of the Clear range's start.
             */

            int idx = BinarySearch(words.Keys, clear.Start.PointerRaw, new MarkupPointerComparer());

            if (idx < 0)
            {
                idx = ~idx;
                idx--;
                idx = Math.Max(0, idx);
            }

            for (; idx < words.Count; idx++)
            {
                MarkupRange range = words.Values[idx];
                // Debug.WriteLine("Testing range: " + range.Text);
                if (!range.Positioned)
                {
                    // Debug.WriteLine("ClearRange: Removing unpositioned word");
                    words.RemoveAt(idx--);
                }
                else if (clear.End.IsLeftOfOrEqualTo(range.Start))
                {
                    // Debug.WriteLine("We've gone far enough--all done");
                    return;
                }
                else if (clear.InRange(range))
                {
                    // Debug.WriteLine("ClearRange: Removing contained range");
                    words.RemoveAt(idx--);
                }
                else if (range.InRange(clear))
                {
                    // Debug.WriteLine("ClearRange: Splitting range");
                    MarkupRange trailingRange = range.Clone();
                    trailingRange.Start.MoveToPointer(clear.End);
                    range.End.MoveToPointer(clear.Start);

                    if (range.IsEmpty())
                    {
                        words.RemoveAt(idx--);
                    }

                    if (!trailingRange.IsEmpty())
                    {
                        Add(trailingRange);
                    }
                }
                else if (range.InRange(clear.End, false))
                {
                    // Debug.WriteLine("ClearRange: Partial overlap, trimming from start of range");
                    words.RemoveAt(idx--);
                    range.Start.MoveToPointer(clear.End);
                    if (!range.IsEmpty())
                    {
                        Add(range);
                    }
                }
                else if (range.InRange(clear.Start, false))
                {
                    // Debug.WriteLine("ClearRange: Partial overlap, trimming from end of range");
                    range.End.MoveToPointer(clear.End);
                    if (range.IsEmpty())
                    {
                        words.RemoveAt(idx--);
                    }
                }
            }

            // Debug.WriteLine("ClearRange: Remaining words in ignore list: " + words.Count);
        }
Esempio n. 21
0
        private void ApplyBlockStyleToRange(_ELEMENT_TAG_ID styleTagId, MarkupRange range, MarkupRange maximumBounds)
        {
            //update the range cling and gravity so it will stick with the re-arranged block content
            range.Start.PushCling(false);
            range.Start.PushGravity(_POINTER_GRAVITY.POINTER_GRAVITY_Left);
            range.End.PushCling(false);
            range.End.PushGravity(_POINTER_GRAVITY.POINTER_GRAVITY_Right);

            try
            {
                MarkupPointer deeperPoint    = GetDeeperPoint(range.Start, range.End);
                MarkupPointer insertionPoint = _markupServices.CreateMarkupPointer(deeperPoint);
                insertionPoint.Cling = false;

                //if the insertion point parent block contains content, split the block.  If the parent
                //block is now empty, then just delete the parent block.
                IHTMLElement parentBlock =
                    insertionPoint.GetParentElement(
                        ElementFilters.CreateCompoundElementFilter(ElementFilters.BLOCK_ELEMENTS,
                                                                   new IHTMLElementFilter(IsSplitStopElement)));

                //temporarily stage the range content at the end of the document so that the split
                //operation doesn't damage the original range content
                MarkupRange stagedBlockContent = _markupServices.CreateMarkupRange();
                stagedBlockContent.Start.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Left;
                stagedBlockContent.End.Gravity   = _POINTER_GRAVITY.POINTER_GRAVITY_Right;
                stagedBlockContent.Start.MoveAdjacentToElement(GetBodyElement(), _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd);
                stagedBlockContent.End.MoveToPointer(stagedBlockContent.Start);

                MarkupPointer stagedBlockInsertionPoint = _markupServices.CreateMarkupPointer(GetBodyElement(), _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd);

                stagedBlockInsertionPoint.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Right;

                // Pass over all opening elements between parent's adj_beforeend and the start of selection (range.start)
                // Any element (_enterscope) that is not closed before the close of selection is essentially
                // containing the selection completely, and needs to be copied into the staging area.
                // ex:   <p><a href="http://msn.com">abc[selection]def</a></p>
                // Here, the <a> element encloses completely the selection and needs to be explicitly copied to the
                // staging area.
                for (MarkupPointer i = _markupServices.CreateMarkupPointer(parentBlock, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
                     i.IsLeftOf(range.Start); i.Right(true))
                {
                    MarkupContext iContext = i.Right(false);

                    if (iContext.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope && iContext.Element is IHTMLAnchorElement)
                    {
                        MarkupPointer j = _markupServices.CreateMarkupPointer(iContext.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd);
                        if (j.IsRightOfOrEqualTo(range.End))
                        {
                            // Copy the tag at posn. i to location stagedBlockInsertionPoint
                            // This is openning tag. Closing tag will be
                            // automatically added by MSHTML.
                            MarkupPointer i1 = i.Clone();
                            i1.Right(true);
                            _markupServices.Copy(i, i1, stagedBlockInsertionPoint);
                            // Skip over the closing tag, so stagedBlockInsertionPoint points between the openning and the closing
                            stagedBlockInsertionPoint.Left(true);
                        }
                        j.Unposition();
                    }
                }

                //move the range content into the staged position
                _markupServices.Move(range.Start, range.End, stagedBlockInsertionPoint); stagedBlockInsertionPoint.Unposition();

                bool splitBlock = !RemoveEmptyParentBlock(range.Clone(), parentBlock, maximumBounds);

                // If the range endpoint NOT chosen as the insertion point lies in a different block element, and
                // that parent block element is now empty, then just delete the parent block.
                MarkupPointer shallowerPoint    = (deeperPoint.IsEqualTo(range.Start)) ? range.End : range.Start;
                MarkupPointer nonInsertionPoint = _markupServices.CreateMarkupPointer(shallowerPoint);

                IHTMLElement otherParentBlock =
                    nonInsertionPoint.GetParentElement(
                        ElementFilters.CreateCompoundElementFilter(ElementFilters.BLOCK_ELEMENTS,
                                                                   new IHTMLElementFilter(IsSplitStopElement)));
                if (otherParentBlock.sourceIndex != parentBlock.sourceIndex)
                {
                    RemoveEmptyParentBlock(range.Clone(), otherParentBlock, maximumBounds);
                }

                if (splitBlock)
                {
                    //split the block at the insertion point
                    SplitBlockForApplyingBlockStyles(insertionPoint, maximumBounds);
                }

                //move the staged block content back to the insertion point and setup the range pointers
                //to wrap the re-inserted block content.
                range.Start.MoveToPointer(insertionPoint);
                range.End.MoveToPointer(insertionPoint);
                _markupServices.Move(stagedBlockContent.Start, stagedBlockContent.End, insertionPoint);

                //Note: the range is now re-positioned around the same content, but all of the parent
                //elements have been closed to prepare for getting new parent block elements around the
                //range

                //convert the range's content into block regions and remove block elements that were
                //parenting the regions.
                InnerBlockRegion[] blockRegions = GetNormalizedBlockContentRegions(range);

                //update all of the block regions with the desired new block style element
                foreach (InnerBlockRegion blockRegion in blockRegions)
                {
                    IHTMLElement newParentElement = WrapRangeInBlockElement(blockRegion.ContentRange, styleTagId);

                    // The old parent element may have had an alignment set on it.
                    IHTMLElement oldParentElement = blockRegion.OldParentElement ?? parentBlock;
                    if (oldParentElement != null)
                    {
                        string oldAlignment = oldParentElement.getAttribute("align", 2) as string;
                        if (!String.IsNullOrEmpty(oldAlignment))
                        {
                            newParentElement.setAttribute("align", oldAlignment, 0);
                        }
                    }
                }
            }
            finally
            {
                range.Start.PopCling();
                range.Start.PopGravity();
                range.End.PopCling();
                range.End.PopGravity();
            }
        }
Esempio n. 22
0
 public SelectionPreserver(MarkupRange selectedMarkupRange)
 {
     _preservedMarkupRange = selectedMarkupRange.Clone();
     _preservedMarkupRange.Start.Cling = true;
     _preservedMarkupRange.End.Cling = true;
 }