protected virtual void Deselect()
        {
            MarkupRange range = EditorContext.MarkupServices.CreateMarkupRange(HTMLElement);

            range.Start.MoveAdjacentToElement(HTMLElement, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);
            range.Collapse(true);
            range.ToTextRange().select();
        }
Beispiel #2
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);
        }
        private MarkupRange AdjustSelection()
        {
            MarkupRange selection = CreateMaxSafeRange(SelectedMarkupRange);

            if (selection.IsEmpty())
            {
                MarkupRange editableRange = MarkupHelpers.GetEditableRange(selection.Start.CurrentScope, MarkupServices);
                MarkupPointerMoveHelper.MoveUnitBounded(selection.Start,
                                                        MarkupPointerMoveHelper.MoveDirection.LEFT,
                                                        MarkupPointerAdjacency.BeforeVisible | MarkupPointerAdjacency.BeforeEnterScope,
                                                        editableRange.Start);
                selection.Collapse(true);
            }
            selection.ToTextRange().select();
            return(selection);
        }
Beispiel #4
0
        internal bool Restore(MarkupRange selection, MarkupRange bounds)
        {
            if (initialMarkup == null)
            {
                return(false);
            }

            NormalizeBounds(ref bounds);

            /*
             *          if (initialMarkup != bounds.HtmlText)
             *          {
             *              Trace.Fail("Unexpected markup");
             *              Trace.WriteLine(initialMarkup);
             *              Trace.WriteLine(bounds.HtmlText);
             *              return false;
             *          }
             */

            selection.Start.MoveToPointer(bounds.Start);

            if (movesRight == int.MaxValue)
            {
                selection.Start.MoveToPointer(bounds.End);
            }
            else
            {
                for (int i = 0; i < movesRight; i++)
                {
                    selection.Start.Right(true);
                }
            }

            for (int i = 0; i < charsLeft; i++)
            {
                selection.Start.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_PREVCHAR);
            }

            selection.Collapse(true);
            selection.ToTextRange().select();

            Debug.Assert(bounds.InRange(selection, true), "Selection was out of bounds");

            return(true);
        }
        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 static void ChangeElementTagIds(MshtmlMarkupServices markupServices, MarkupRange selection, _ELEMENT_TAG_ID[] tagBefore, _ELEMENT_TAG_ID tagAfter)
        {
            HtmlStyleHelper htmlStyleHelper = new HtmlStyleHelper(markupServices);

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

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

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

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

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


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

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

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

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

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

            if (selectionStartedEmpty)
            {
                selection.Start.MoveToMarkupPosition(selection.Start.Container, rangeToChange.Start.MarkupPosition + parentStartDiff);
                selection.Collapse(true);
            }
        }
        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);
        }
        /// <summary>
        /// Advance to next word
        /// </summary>
        public void Next()
        {
            currentWordRange.End.MoveToPointer(currentVirtualPosition);

            do
            {
                //advance the start pointer to the beginning of next word
                if (!currentWordRange.End.IsEqualTo(selectionRange.Start)) //avoids skipping over the first word
                {
                    //fix bug 1848 - move the start to the end pointer before advancing to the next word
                    //this ensures that the "next begin" is after the current selection.
                    currentWordRange.Start.MoveToPointer(currentWordRange.End);
                    currentWordRange.Start.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_PREVWORDBEGIN);

                    currentWordRange.Start.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_NEXTWORDBEGIN);
                }
                else
                {
                    //Special case for putting the start pointer at the beginning of the
                    //correct word when the selection may or may not be already adjacent
                    //to the the beginning of the word.
                    //Note: theoretically, the selection adjustment in the constructor
                    //guarantees that we will be flush against the first word, so we could
                    //probably do nothing, but it works, so we'll keep it.
                    currentWordRange.Start.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_NEXTWORDEND);
                    currentWordRange.Start.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_PREVWORDBEGIN);
                }

                //advance the end pointer to the end of next word
                currentWordRange.End.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_NEXTWORDEND);

                if (currentWordRange.Start.IsRightOf(currentWordRange.End))
                {
                    //Note: this was a condition that caused several bugs that caused us to stop
                    //spell-checking correctly, so this logic is here in case we still have edge
                    //cases that trigger it.
                    //This should not occur anymore since we fixed several causes of this
                    //condition by setting the currentWordRange gravity, and detecting case where
                    //the selection may or may-not start at the beginning of a word.
                    Debug.Fail("word start jumped past word end");

                    //if this occurred, it was probably because start was already at the beginning
                    //of the correct word before it was moved.  To resolve this situation, we
                    //move the start pointer back to the beginning of the word that the end pointer
                    //is at. Since the End pointer always advances on each iteration, this should not
                    //cause an infinite loop. The worst case scenario is that we check the same word
                    //more than once.
                    currentWordRange.Start.MoveToPointer(currentWordRange.End);
                    currentWordRange.Start.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_PREVWORDBEGIN);
                }
            } while(MarkupHelpers.GetRangeTextFast(currentWordRange) == null &&
                    currentWordRange.End.IsLeftOf(selectionRange.End));

            currentVirtualPosition.MoveToPointer(currentWordRange.End);

            if (currentWordRange.End.IsRightOf(selectionRange.End))
            {
                //then collapse the range so that CurrentWord returns Empty;
                currentWordRange.Start.MoveToPointer(currentWordRange.End);
            }
            else
            {
                MarkupRange testRange = currentWordRange.Clone();
                testRange.Collapse(false);
                testRange.End.MoveUnitBounded(_MOVEUNIT_ACTION.MOVEUNIT_NEXTCHAR, selectionRange.End);
                if (MarkupHelpers.GetRangeHtmlFast(testRange) == ".")
                {
                    currentWordRange.End.MoveToPointer(testRange.End);
                }
            }
        }
Beispiel #9
0
        private void ReplaceDashes(MarkupPointer blockBoundary)
        {
            if (!AutoreplaceSettings.EnableHyphenReplacement)
            {
                return;
            }

            MarkupRange emRange = _currentSelection.Clone();

            for (int i = 0; i < 3 && emRange.Start.IsRightOf(blockBoundary); i++)
            {
                emRange.Start.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_PREVWORDBEGIN);
            }
            string emText = emRange.Text ?? "";

            if (emText.Contains("-"))
            {
                // \u00A0 = non breaking space
                Regex regex = new Regex(@"[^\s\u00A0\-]([ \u00A0]?(?>--?)[ \u00A0]?)[^\s\u00A0\-]");
                Match match = regex.Match(emText);
                if (match.Success)
                {
                    Debug.Assert(match.Groups.Count == 2, "Matched more than one set of dashes. Expecting only one match.");
                    string      matchValue = match.Groups[1].Value.Replace((char)160, ' ');
                    MarkupRange findRange  = _currentSelection.Clone();

                    // Since we're now doing this matching AFTER a character has been added, we need to jump back.
                    findRange.End.MoveUnitBounded(_MOVEUNIT_ACTION.MOVEUNIT_PREVCHAR, emRange.Start);
                    findRange.Collapse(false);
                    for (int i = 0; i < matchValue.Length; i++)
                    {
                        findRange.Start.MoveUnitBounded(_MOVEUNIT_ACTION.MOVEUNIT_PREVCHAR, emRange.Start);
                    }

                    for (int i = 0; i < emText.Length; i++)
                    {
                        if (findRange.Text == matchValue)
                        {
                            string replaceText = null;
                            switch (matchValue)
                            {
                            case ("--"):
                            case ("-- "):
                                replaceText = "&#8212;";
                                break;

                            case (" --"):
                            case (" -"):
                                replaceText = "&#160;&#8211;";
                                break;

                            case (" -- "):
                            case (" - "):
                                replaceText = "&#160;&#8211; ";
                                break;

                            case ("-"):
                            case ("- "):
                                break;
                            }

                            if (replaceText != null)
                            {
                                _insertHtml(findRange.Start, findRange.End, replaceText);
                                break;
                            }
                        }
                        findRange.Start.MoveUnitBounded(_MOVEUNIT_ACTION.MOVEUNIT_PREVCHAR, emRange.Start);
                        findRange.End.MoveUnitBounded(_MOVEUNIT_ACTION.MOVEUNIT_PREVCHAR, emRange.Start);
                    }
                }
            }
        }