Пример #1
0
        /// <summary>
        /// WinLive 225587: If the user hits delete when the cursor is just before a table, we want to move the
        /// content at the cursor into the first table cell. This behavior aligns us with Word 2010.
        /// </summary>
        private void TryMoveIntoNextTable(HtmlEditorSelectionOperationEventArgs ea)
        {
            if (!SelectedMarkupRange.IsEmpty() || IsEditFieldSelected)
            {
                return;
            }

            IHTMLElement nextTable = null;
            bool enteredABlockElement = false;
            int numBlockElementsBetweenSelectionAndNextTable = 0;
            IHTMLElement brElement = null;

            MarkupRange postBodyRange = MarkupServices.CreateMarkupRange(PostBodyElement, false);
            postBodyRange.Start.MoveToPointer(SelectedMarkupRange.Start);
            postBodyRange.WalkRange(
                delegate (MarkupRange currentRange, MarkupContext context, string text)
                {
                    if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text ||
                        context.Element == null)
                    {
                        // There is text between the cursor position and the next table. Stop processing and quit.
                        return false;
                    }

                    if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope &&
                        ElementFilters.IsVisibleEmptyElement(context.Element))
                    {
                        if (context.Element is IHTMLBRElement && brElement == null)
                        {
                            // Allow up to one <br> element to be between the cursor position and the next table as
                            // long as its in our parent block element, since it won't cause a line break, e.g.:
                            //  <div>Hello[cursor]<br></div><table>...</table>
                            //  <table><tr><td>Hello[cursor]<br><table>...</table></td></tr></table>
                            brElement = context.Element;
                            return true;
                        }

                        // There is content between the cursor position and the next table. Stop processing and quit.
                        return false;
                    }

                    if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope)
                    {
                        if (context.Element is IHTMLTable)
                        {
                            if (StopTryMoveIntoNextTable(context.Element))
                                return false;

                            // We found the next table so we can stop walking the range.
                            nextTable = context.Element;
                            return false;
                        }

                        if (ElementFilters.IsBlockElement(context.Element) || ElementFilters.IsListElement(context.Element))
                        {
                            // Set a flag so that we know that since starting at the cursor position, we've walked into
                            // a block element, e.g.:
                            //  <div>Hello[cursor]<div>[currentPosition]</div></div>
                            //  <ul><li>Hello[cursor]</li><li>[currentPosition]</li></ul>
                            enteredABlockElement = true;
                        }
                    }

                    if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope)
                    {
                        if (ElementFilters.IsBlockElement(context.Element) || ElementFilters.IsListElement(context.Element))
                        {
                            if (enteredABlockElement)
                            {
                                // We entered and exited a block element without finding a table, e.g.:
                                //  <div>Hello[cursor]<div></div>[currentPosition]</div>
                                //  <ul><li>Hello[cursor]</li><li></li>[currentPosition]</ul>
                                // Stop processing and quit.
                                return false;
                            }
                            else
                            {
                                // We count up the number of block elements we've exited so we know what parent to
                                // remove later, e.g.:
                                //  <div><div><div>Hello[cursor]</div></div>[currentPosition]</div><table>...</table>
                                numBlockElementsBetweenSelectionAndNextTable++;
                            }
                        }
                        else if (ElementFilters.IsTableCellElement(context.Element))
                        {
                            // We exited a table cell element without finding a table. Stop processing and quit.
                            //  <table><tr><td>Hello[cursor]</td>[currPosition]</tr></table>
                            return false;
                        }
                    }

                    // Keep walking the range.
                    return true;
                }, false);

            if (nextTable == null)
            {
                return;
            }

            // First, let's figure out what element the current selection is in.
            IHTMLElement parentBlockElement = SelectedMarkupRange.ParentElement(
                e => ElementFilters.IsListItemElement(e) || ElementFilters.IsTableCellElement(e) ||
                    ((ElementFilters.IsBlockElement(e) || ElementFilters.IsListElement(e)) && --numBlockElementsBetweenSelectionAndNextTable <= 0));

            // This represents the range of markup that we should move into the table.
            MarkupRange currentBlockRange = MarkupServices.CreateMarkupRange(parentBlockElement, false);

            using (IUndoUnit undoUnit = CreateUndoUnit())
            {
                if (brElement != null)
                {
                    if (!currentBlockRange.InRange(brElement))
                    {
                        // There's a <br> causing a line break between the cursor and the next table, so we won't try to move anything.
                        return;
                    }
                    else
                    {
                        // The <br> would cause a line break if we moved it into the <table>, e.g.:
                        //  <div>Hello<br></div><table><tr><td></td></tr></table> - if we moved "Hello<br>" into the
                        //  <td>, the <br> would now cause a line break (although it did not when wrapped in a <div>).
                        HTMLElementHelper.RemoveElement(brElement);
                    }
                }

                // In the case of <div>Some text...|<table>...</table>...</div> - we need to be careful not to remove the <div>.
                if (currentBlockRange.InRange(nextTable))
                {
                    currentBlockRange.Start.MoveAdjacentToElement(parentBlockElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
                    currentBlockRange.End.MoveAdjacentToElement(nextTable, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin);

                    if (ElementFilters.IsTableCellElement(parentBlockElement))
                    {
                        // We use <br>s for line breaks in tables.
                        IHTMLElement[] brElements = currentBlockRange.GetElements(e => e is IHTMLBRElement, true);
                        if (brElements.Length > 0)
                        {
                            // We'll only move the last line, e.g.:
                            //  <table><tr><td>Hello<br>World<table>...<table></td></tr></table> - only move "World" into the nested table.
                            currentBlockRange.Start.MoveAdjacentToElement(brElements[brElements.Length - 1], _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
                        }
                    }

                    parentBlockElement = null;
                }
                else
                {
                    // Fix up the range to only contain inline elements and text, e.g.:
                    //  <div><div><div><em>Hello</em></div></div></div><table>...</table> - we'll only move "<em>Hello</em>" into the table.
                    currentBlockRange.SelectInner();
                    MarkupPointerMoveHelper.MoveUnitBounded(currentBlockRange.Start, MarkupPointerMoveHelper.MoveDirection.LEFT,
                        MarkupPointerAdjacency.BeforeExitBlock, parentBlockElement);
                    MarkupPointerMoveHelper.MoveUnitBounded(currentBlockRange.End, MarkupPointerMoveHelper.MoveDirection.RIGHT,
                        MarkupPointerAdjacency.BeforeExitBlock, parentBlockElement);
                }

                // We're ready to move content into the <table> we found, now find the first <td> inside of it.
                MarkupPointer p = MarkupServices.CreateMarkupPointer(nextTable, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
                IHTMLElement firstTd = p.SeekElementRight(e => e is IHTMLTableCell,
                    MarkupServices.CreateMarkupPointer(nextTable, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd));
                if (firstTd != null)
                {
                    if (MarkupServices.CreateMarkupRange(firstTd, false).IsEmptyOfContent())
                    {
                        // The table behavior leaves an empty space in the table, so make sure we remove it before inserting.
                        firstTd.innerHTML = String.Empty;
                    }

                    // Move the content at the cursor into the <td>.
                    MarkupPointer afterBeginFirstTd = MarkupServices.CreateMarkupPointer(firstTd, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
                    afterBeginFirstTd.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Right;
                    MarkupServices.Move(currentBlockRange.Start, currentBlockRange.End, afterBeginFirstTd);

                    // Remove the original container around the cursor if necessary, e.g.:
                    //  <p>Hello[cursor]</p><table><tr><td></td></tr></table> should become =>
                    //  <table><tr><td>Hello[cursor]</td></tr></table>
                    if (parentBlockElement != null)
                    {
                        if (ElementFilters.IsListItemElement(parentBlockElement))
                        {
                            // If this is the only list item in the list, then we want to remove the list too, e.g.:
                            //  <ul><li>Hello[cursor]</li></ul><table><tr><td></td></tr></table> should become =>
                            //  <table><tr><td>Hello[cursor]</td></tr></table>
                            IHTMLElement listElement = parentBlockElement.parentElement;
                            if (listElement != null && ElementFilters.IsListElement(listElement) &&
                                ((IHTMLElementCollection)listElement.children).length == 1)
                            {
                                HTMLElementHelper.RemoveElement(listElement);
                            }
                        }

                        HTMLElementHelper.RemoveElement(parentBlockElement);
                    }

                    // Move the cursor inside the table.
                    MarkupServices.CreateMarkupRange(afterBeginFirstTd, afterBeginFirstTd).ToTextRange().select();

                    // Make sure the content gets spellchecked since we just moved it.
                    _damageServices.AddDamage(MarkupServices.CreateMarkupRange(firstTd, false));

                    ea.Handled = true;
                    undoUnit.Commit();
                }
            }
        }
Пример #2
0
        protected virtual void OnClear(HtmlEditorSelectionOperationEventArgs ea)
        {
            if (HandleClear != null)
            {
                foreach (HtmlEditorSelectionOperationEventHandler handler in HandleClear.GetInvocationList())
                {
                    handler(ea);

                    if (ea.Handled)
                        break;
                }
            }
        }
Пример #3
0
        private void ClearSelection(IHtmlEditorSelection selection)
        {
            using (_damageServices.CreateDeleteDamageTracker(selection.SelectedMarkupRange))
            {
                // allow override by components
                HtmlEditorSelectionOperationEventArgs ea = new HtmlEditorSelectionOperationEventArgs(selection);
                OnClear(ea);

                // if no override then execute
                if (!ea.Handled)
                {
                    GetMshtmlCommand(IDM.DELETE).Execute();
                    // Clear out any state maintained by MSHTML regarding the backcolor.
                    if (selection.SelectedMarkupRange.IsTagId(_ELEMENT_TAG_ID.TAGID_FONT, false))
                        GetMshtmlCommand(IDM.BACKCOLOR).Execute(null);
                }

                FireSelectionChanged();
            }
        }
Пример #4
0
        private void CopySelection(IHtmlEditorSelection selection)
        {
            // allow override by components
            HtmlEditorSelectionOperationEventArgs ea = new HtmlEditorSelectionOperationEventArgs(selection);
            OnCopy(ea);

            // if no override then execute
            if (!ea.Handled)
                GetMshtmlCommand(IDM.COPY).Execute();
        }
Пример #5
0
        private void CutSelection(IHtmlEditorSelection selection)
        {
            using (_damageServices.CreateDeleteDamageTracker(selection.SelectedMarkupRange))
            {
                // allow override by components
                HtmlEditorSelectionOperationEventArgs ea = new HtmlEditorSelectionOperationEventArgs(selection);
                OnCut(ea);

                // if no override then execute
                if (!ea.Handled)
                    GetMshtmlCommand(IDM.CUT).Execute();
            }
        }
        private void EditorContext_HandleCut(HtmlEditorSelectionOperationEventArgs ea)
        {
            if (Selected && MultipleCellsSelected && !EntireTableSelected)
            {
                EditorContext.ExecuteCommand(IDM.COPY);

                using (IUndoUnit undoUnit = EditorContext.CreateUndoUnit())
                {
                    TableEditor.ClearCells(EditorContext);
                    undoUnit.Commit();
                }

                ea.Handled = true;
            }
        }