예제 #1
0
        internal SelectionPositionPreservationCookie(MshtmlMarkupServices markupServices, MarkupRange selection, MarkupRange bounds)
        {
            if (!selection.IsEmpty())
            {
                return;
            }

            initialMarkup = bounds.HtmlText;

            NormalizeBounds(ref bounds);

            MarkupPointer p = bounds.Start.Clone();

            movesRight = 0;
            while (p.IsLeftOf(selection.Start))
            {
                movesRight++;
                p.Right(true);
                if (p.IsRightOf(bounds.End))
                {
                    movesRight = int.MaxValue;
                    p.MoveToPointer(bounds.End);
                    break;
                }
            }

            charsLeft = 0;
            while (p.IsRightOf(selection.Start))
            {
                charsLeft++;
                p.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_PREVCHAR);
            }
        }
        private bool IsEditableSelection()
        {
            MarkupRange selectedRange = SelectedMarkupRange;

            if (MarkupHelpers.GetEditableRange(selectedRange.Start.CurrentScope, MarkupServices) != null)
            {
                if (selectedRange.IsEmpty() || MarkupHelpers.GetEditableRange(selectedRange.Start.CurrentScope, MarkupServices) != null)
                {
                    return(true);
                }
            }
            return(false);
        }
예제 #3
0
        /// <summary>
        /// Notify the data format handler that data was dropped and should be inserted into
        /// the document at whatever insert location the handler has internally tracked.
        /// </summary>
        /// <param name="action"></param>
        public override bool DataDropped(DataAction action)
        {
            if (currentCaretLocation == null)
            {
                return(false);
            }

            // create two markup pointers that map to the location of the caret
            MarkupPointer begin = EditorContext.MarkupServices.CreateMarkupPointer();
            MarkupPointer end   = EditorContext.MarkupServices.CreateMarkupPointer();

            EditorContext.MarkupServices.MoveMarkupPointerToCaret(currentCaretLocation, begin);
            MarkupPointerMoveHelper.PerformImageBreakout(begin);

            //optimize the drop location to keep it from being in an unexpected location (fixes bug 395224)
            if (EditorContext.ShouldMoveDropLocationRight(begin))
            {
                begin.Right(true);
            }

            //synchronize the end pointer with the being pointer
            end.MoveToPointer(begin);

            MarkupRange selectedRange = EditorContext.SelectedMarkupRange;

            // WinLive 91888 Photomail image drag drop loses images
            //if (!selectedRange.IsEmpty() && selectedRange.InRange(end))
            if (!selectedRange.IsEmpty() && selectedRange.InRange(end, false))
            {
                //the drop location is over the drag source location, so don't so anything.
                return(false);
            }

            // Forces a SelectionChanged event so that the correct behaviors around the drop location are activated.
            // For example, one side effect of this call is that the OnEditableRegionFocusChanged event is fired, which
            // sets whether the current drop location in the canvas supports images, html and/or text.
            MarkupRange dropRange = EditorContext.MarkupServices.CreateMarkupRange(begin, end);

            dropRange.ToTextRange().select();

            try
            {
                // insert the data at the current insertion point
                return(InsertData(action, begin, end));
            }
            catch (Exception e)
            {
                Trace.Fail(e.Message, e.StackTrace);
                return(false);
            }
        }
예제 #4
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();
            }
        }
        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);
        }
예제 #6
0
        private void buttonLoad_Click(object sender, EventArgs e)
        {
            MarkupRange selection = GetSelectedMarkupRange();

            if (selection.IsEmpty())
            {
                this.listViewStyle.Enabled = true;

                IHTMLElement2     element = (IHTMLElement2)selection.Start.CurrentScope;
                IHTMLCurrentStyle style   = element.currentStyle;
                RefreshStyleItems(style);
            }
            else
            {
                this.listViewStyle.Enabled = false;
            }
        }
        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);
                }
            }
        }
        private void HandleEnterKey(HtmlEventArgs e)
        {
            //pressing the enter key on an empty line is used as a gesture for exiting the blockquote
            //If this situation is encountered, move the current empty block element outside of the blockquote
            MarkupRange selection = EditorContext.Selection.SelectedMarkupRange;

            if (selection.IsEmpty())
            {
                MarkupPointer selectionPoint = EditorContext.MarkupServices.CreateMarkupPointer(selection.Start);
                selectionPoint.Cling = true;

                IHTMLElement currBlock      = selection.Start.CurrentBlockScope();
                MarkupRange  currBlockRange = EditorContext.MarkupServices.CreateMarkupRange(currBlock, false);
                if (currBlockRange.IsEmptyOfContent())
                {
                    currBlockRange.MoveToElement(currBlock, true);

                    // Make sure there is no content between the end of this block range and the end of the blockquote.
                    MarkupPointer afterEndCurrBlock   = EditorContext.MarkupServices.CreateMarkupPointer(currBlock, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
                    MarkupPointer beforeEndBlockQuote = EditorContext.MarkupServices.CreateMarkupPointer(HTMLElement, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd);
                    MarkupRange   restOfBlockQuote    = EditorContext.MarkupServices.CreateMarkupRange(afterEndCurrBlock, beforeEndBlockQuote);
                    if (!restOfBlockQuote.IsEmpty() || !restOfBlockQuote.IsEmptyOfContent())
                    {
                        return;
                    }

                    //create a pointer for the new location that the block element will be moved to.
                    MarkupPointer insertionPoint =
                        EditorContext.MarkupServices.CreateMarkupPointer(HTMLElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);

                    //move the current empty block to the DOM location after the blockquote
                    EditorContext.MarkupServices.Move(currBlockRange.Start, currBlockRange.End, insertionPoint);
                    currBlockRange.MoveToElement(currBlock, false);

                    //adjust the selection to the new location of the block element.
                    currBlockRange.Start.MoveToPointer(selectionPoint);
                    currBlockRange.End.MoveToPointer(selectionPoint);
                    currBlockRange.ToTextRange().select();

                    //cancel the key down event so that the editor doesn't try to handle it
                    e.Cancel();
                }
            }
        }
        public static void ChangeElementTagIds(MshtmlMarkupServices markupServices, MarkupRange selection, _ELEMENT_TAG_ID[] tagBefore, _ELEMENT_TAG_ID tagAfter)
        {
            HtmlStyleHelper htmlStyleHelper = new HtmlStyleHelper(markupServices);

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

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

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

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

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


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

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

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

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

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

            if (selectionStartedEmpty)
            {
                selection.Start.MoveToMarkupPosition(selection.Start.Container, rangeToChange.Start.MarkupPosition + parentStartDiff);
                selection.Collapse(true);
            }
        }
        public 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));
        }
        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);
        }
        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);
        }