Example #1
0
        private void ApplyBlockFormatToContentSelection(MarkupRange selection, _ELEMENT_TAG_ID styleTagId, MarkupRange maximumBounds)
        {
            MarkupRange[] stylableBlockRegions = GetSelectableBlockRegions(selection);
            if (stylableBlockRegions.Length > 0)
            {
                //
                // We want to make sure that the selection reflects only the
                // blocks that were changed. Unposition the start and end
                // pointers and then make sure they cover the stylable block
                // regions, no more, no less.
                selection.Start.Unposition();
                selection.End.Unposition();

                foreach (MarkupRange range in stylableBlockRegions)
                {
                    ApplyBlockStyleToRange(styleTagId, range, maximumBounds);

                    if (!selection.Start.Positioned || range.Start.IsLeftOf(selection.Start))
                    {
                        selection.Start.MoveToPointer(range.Start);
                    }
                    if (!selection.End.Positioned || range.End.IsRightOf(selection.End))
                    {
                        selection.End.MoveToPointer(range.End);
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        /// Creates an element with the specified tag.
        /// </summary>
        /// <param name="tagID">specifies the type of tag to create</param>
        /// <param name="attributes">specifies the attributes of the element</param>
        /// <returns>the newly created element</returns>
        public IHTMLElement CreateElement(_ELEMENT_TAG_ID tagID, string attributes)
        {
            IHTMLElement element;

            MarkupServices.CreateElement(tagID, attributes, out element);
            return(element);
        }
Example #3
0
        /// <summary>
        /// Returns the tag name given the identifier (ID).
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        public string GetNameForTagId(_ELEMENT_TAG_ID tagId)
        {
            IntPtr p;

            MarkupServices.GetNameForTagID(tagId, out p);
            return(Marshal.PtrToStringBSTR(p));
        }
 internal SemanticHtmlElementInfo(string htmlName, _ELEMENT_TAG_ID tagId, string displayName, string htmlId, CommandId commandId)
 {
     _htmlName    = htmlName;
     _tagId       = tagId;
     _displayName = displayName;
     _htmlId      = htmlId;
     _commandId   = commandId;
 }
        public void RemoveElementsByTagId(_ELEMENT_TAG_ID tagId, bool onlyIfNoAttributes)
        {
            if (tagId == _ELEMENT_TAG_ID.TAGID_NULL)
            {
                return;
            }

            // Remove the tagId up the parent chain
            IHTMLElement currentElement = ParentElement();

            while (currentElement != null)
            {
                if (MarkupServices.GetElementTagId(currentElement) == tagId &&
                    (!onlyIfNoAttributes || !HTMLElementHelper.HasMeaningfulAttributes(currentElement)))
                {
                    try
                    {
                        MarkupServices.RemoveElement(currentElement);
                    }
                    catch (COMException e)
                    {
                        Trace.Fail(String.Format("Failed to remove element ({0}) with error: {1}",
                                                 currentElement.outerHTML, // {0}
                                                 e                         // {1}
                                                 ));
                    }
                }
                currentElement = currentElement.parentElement;
            }

            // Remove any other instances
            IHTMLElement[] elements =
                GetElements(ElementFilters.CreateTagIdFilter(MarkupServices.GetNameForTagId(tagId)), false);
            foreach (IHTMLElement e in elements)
            {
                if (MarkupServices.GetElementTagId(e) == tagId &&
                    (!onlyIfNoAttributes || !HTMLElementHelper.HasMeaningfulAttributes(e)))
                {
                    try
                    {
                        MarkupServices.RemoveElement(e);
                    }
                    catch (COMException ex)
                    {
                        Trace.Fail(String.Format("Failed to remove element ({0}) with error: {1}",
                                                 e.outerHTML, // {0}
                                                 ex           // {1}
                                                 ));
                    }
                }
            }
        }
Example #6
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);
        }
Example #7
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 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();
        }
Example #9
0
        private IHTMLElement WrapRangeInBlockElement(MarkupRange blockRegion, _ELEMENT_TAG_ID styleTagId)
        {
            MarkupRange insertionRange = _markupServices.CreateMarkupRange();
            //create the new block element
            IHTMLElement newBlockElement = _markupServices.CreateElement(styleTagId, null);

            //insert the new block element in front of the block content
            insertionRange.Start.MoveToPointer(blockRegion.Start);
            insertionRange.End.MoveToPointer(blockRegion.Start);
            _markupServices.InsertElement(newBlockElement, insertionRange.Start, insertionRange.End);

            //move the block content inside the new block element
            insertionRange.Start.MoveAdjacentToElement(newBlockElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
            blockRegion.Start.MoveAdjacentToElement(newBlockElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
            _markupServices.Move(blockRegion.Start, blockRegion.End, insertionRange.Start);
            return(newBlockElement);
        }
        private IHTMLElement WrapRangeInSpanElement(_ELEMENT_TAG_ID tagId, string attributes, MarkupRange spanRange)
        {
            MarkupRange  insertionRange = _markupServices.CreateMarkupRange();
            IHTMLElement newSpanElement = _markupServices.CreateElement(tagId, attributes);

            //insert the new span element in front of the span content
            insertionRange.Start.MoveToPointer(spanRange.Start);
            insertionRange.End.MoveToPointer(spanRange.Start);
            _markupServices.InsertElement(newSpanElement, insertionRange.Start, insertionRange.End);

            //move the span content inside the new span element
            insertionRange.Start.MoveAdjacentToElement(newSpanElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
            spanRange.Start.MoveAdjacentToElement(newSpanElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);

            _markupServices.Move(spanRange.Start, spanRange.End, insertionRange.Start);
            return(newSpanElement);
        }
        /// <summary>
        /// Initializes a new instance of the DefaultBlockElement class.
        /// </summary>
        /// <param name="tagId">The tag id associated with the default block element.</param>
        /// <param name="tagName">The tag name associated with the default block element.</param>
        /// <param name="numberOfNewLinesToReplace">The number of plain-text CRLFs that should be replaced when
        /// inserting the default block element. This is used when converting plain-text to HTML in order to maintain
        /// similar rendering between plain-text and  HTML. Must be greater than zero.</param>
        protected DefaultBlockElement(_ELEMENT_TAG_ID tagId, string tagName, int numberOfNewLinesToReplace)
        {
            if (!Enum.IsDefined(typeof(_ELEMENT_TAG_ID), tagId))
            {
                throw new ArgumentException("tagId");
            }

            if (String.IsNullOrEmpty(tagName))
            {
                throw new ArgumentException("tagName");
            }

            if (numberOfNewLinesToReplace < 1)
            {
                throw new ArgumentOutOfRangeException("numberOfNewLinesToReplace");
            }

            this.BeginTag = String.Format("<{0}>", tagName);
            this.EndTag = String.Format("</{0}>", tagName);
            this.TagId = tagId;
            this.TagName = tagName;
            this.NumberOfNewLinesToReplace = numberOfNewLinesToReplace;
        }
Example #12
0
        /// <summary>
        /// Initializes a new instance of the DefaultBlockElement class.
        /// </summary>
        /// <param name="tagId">The tag id associated with the default block element.</param>
        /// <param name="tagName">The tag name associated with the default block element.</param>
        /// <param name="numberOfNewLinesToReplace">The number of plain-text CRLFs that should be replaced when
        /// inserting the default block element. This is used when converting plain-text to HTML in order to maintain
        /// similar rendering between plain-text and  HTML. Must be greater than zero.</param>
        protected DefaultBlockElement(_ELEMENT_TAG_ID tagId, string tagName, int numberOfNewLinesToReplace)
        {
            if (!Enum.IsDefined(typeof(_ELEMENT_TAG_ID), tagId))
            {
                throw new ArgumentException("tagId");
            }

            if (String.IsNullOrEmpty(tagName))
            {
                throw new ArgumentException("tagName");
            }

            if (numberOfNewLinesToReplace < 1)
            {
                throw new ArgumentOutOfRangeException("numberOfNewLinesToReplace");
            }

            this.BeginTag = String.Format("<{0}>", tagName);
            this.EndTag   = String.Format("</{0}>", tagName);
            this.TagId    = tagId;
            this.TagName  = tagName;
            this.NumberOfNewLinesToReplace = numberOfNewLinesToReplace;
        }
        /// <summary>
        /// Determines if a range has a particular _ELEMENT_TAG_ID applied.
        /// </summary>
        /// <param name="tagId"></param>
        /// <param name="partially">If true, then IsTagId will return true if any part of it is contained within a tagId element.
        ///                         If false, then IsTagId will return true only if the range is entirely contained within a tagId element.</param>
        /// <returns></returns>
        public bool IsTagId(_ELEMENT_TAG_ID tagId, bool partially)
        {
            // This first block of code will return true if the range is entirely contained within an element with the given tagId.
            IHTMLElement currentElement = ParentElement();

            while (currentElement != null)
            {
                if (MarkupServices.GetElementTagId(currentElement) == tagId)
                {
                    return(true);
                }

                currentElement = currentElement.parentElement;
            }

            // This second block of code will return true if the range is partially contained within an element with the given tagId.
            if (partially)
            {
                IHTMLElement[] elements = GetElements(ElementFilters.CreateTagIdFilter(MarkupServices.GetNameForTagId(tagId)), false);
                return(elements.Length > 0);
            }

            return(false);
        }
        private void ApplyBlockFormatToContentSelection(MarkupRange selection, _ELEMENT_TAG_ID styleTagId, MarkupRange maximumBounds)
        {
            MarkupRange[] stylableBlockRegions = GetSelectableBlockRegions(selection);
            if (stylableBlockRegions.Length > 0)
            {
                //
                // We want to make sure that the selection reflects only the
                // blocks that were changed. Unposition the start and end
                // pointers and then make sure they cover the stylable block
                // regions, no more, no less.
                selection.Start.Unposition();
                selection.End.Unposition();

                foreach (MarkupRange range in stylableBlockRegions)
                {
                    ApplyBlockStyleToRange(styleTagId, range, maximumBounds);

                    if (!selection.Start.Positioned || range.Start.IsLeftOf(selection.Start))
                        selection.Start.MoveToPointer(range.Start);
                    if (!selection.End.Positioned || range.End.IsRightOf(selection.End))
                        selection.End.MoveToPointer(range.End);
                }
            }
        }
        private IHTMLElement WrapRangeInBlockElement(MarkupRange blockRegion, _ELEMENT_TAG_ID styleTagId)
        {
            MarkupRange insertionRange = _markupServices.CreateMarkupRange();
            //create the new block element
            IHTMLElement newBlockElement = _markupServices.CreateElement(styleTagId, null);

            //insert the new block element in front of the block content
            insertionRange.Start.MoveToPointer(blockRegion.Start);
            insertionRange.End.MoveToPointer(blockRegion.Start);
            _markupServices.InsertElement(newBlockElement, insertionRange.Start, insertionRange.End);

            //move the block content inside the new block element
            insertionRange.Start.MoveAdjacentToElement(newBlockElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
            blockRegion.Start.MoveAdjacentToElement(newBlockElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);
            _markupServices.Move(blockRegion.Start, blockRegion.End, insertionRange.Start);
            return newBlockElement;
        }
 private MarkupRange ApplyInlineTagToBlockFreeSelection(_ELEMENT_TAG_ID tagId, string attributes, MarkupRange blockFreeSelection)
 {
     // @RIBBON TODO: May want to be a bit more sophisticated and eliminate redundant tags
     return(_markupServices.CreateMarkupRange(WrapRangeInSpanElement(tagId, attributes, blockFreeSelection)));
 }
Example #17
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();
            }
        }
        /// <summary>
        /// Returns true if the element is not natively supported by MSHTML's editing commands and should therefore be
        /// replaced.
        /// </summary>
        /// <param name="element">The element to consider replacing.</param>
        /// <param name="tagId">The tag to replace the element with.</param>
        /// <returns>true if the element should be replaced and false otherwise.</returns>
        private bool TryGetReplacement(IHTMLElement element, out _ELEMENT_TAG_ID tagId)
        {
            if (element != null)
            {
                if (IsNonSupportedStrikeThroughElement(element))
                {
                    tagId = _ELEMENT_TAG_ID.TAGID_STRIKE;
                    return true;
                }
            }

            tagId = _ELEMENT_TAG_ID.TAGID_UNKNOWN;
            return false;
        }
        private void ApplyInlineTag(_ELEMENT_TAG_ID tagId, string attributes, bool toggle)
        {
            if (_initialDocumentLoaded)
            {
                MarkupRange selectedMarkupRange = SelectedMarkupRange;
                if (IsValidContentInsertionPoint(selectedMarkupRange))
                {
                    using (IUndoUnit undo = CreateUndoUnit())
                    {
                        MarkupRange selection = SelectedMarkupRange;
                        MarkupRange newSelection;
                        using (DamageServices.CreateDamageTracker(selection, true))
                        {
                            newSelection = HtmlStyleHelper.ApplyInlineTag(MarkupServices, tagId, attributes, selection, toggle);

                            if (!newSelection.Positioned)
                            {
                                Debug.Fail("Shouldn't have applied inline tag because there was nothing to apply it to.");
                                return;
                            }
                        }

                        if (newSelection.IsEmpty())
                        {
                            DisplayServices.TraceMoveToMarkupPointer(CaretPositionDisplayPointer, newSelection.Start);
                            SynchronizeCaretWithDisplayPointer(CaretPositionDisplayPointer, true);
                        }
                        else
                        {
                            //reselect the selected text.
                            newSelection.ToTextRange().select();
                        }

                        undo.Commit();
                    }
                }
            }
        }
        /// <summary>
        /// Returns the markup pointer to the position of the first exit scope of type tagId or type terminatingTagId which follows this markup range.
        /// Returns null if text exists between the range and such an exit scope, or if there is no such exit scope.
        /// </summary>
        /// <param name="terminatingTagId"></param>
        /// <returns></returns>
        internal MarkupPointer NextExitScopeWithoutInterveningText(MarkupRange selection, _ELEMENT_TAG_ID tagId, _ELEMENT_TAG_ID terminatingTagId, out bool primaryTagIdMatch)
        {
            MarkupContext context = new MarkupContext();

            MarkupPointer pointer = selection.End.Clone();

            primaryTagIdMatch = false;

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

                switch (context.Context)
                {
                case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_None:
                    return(null);

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

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

                break;

                case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope:
                case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope:
                    break;

                case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text:
                    return(null);
                }
            }
        }
 /// <summary>
 /// Creates an element with the specified tag.
 /// </summary>
 /// <param name="tagID">specifies the type of tag to create</param>
 /// <param name="attributes">specifies the attributes of the element</param>
 /// <returns>the newly created element</returns>
 public IHTMLElement CreateElement(_ELEMENT_TAG_ID tagID, string attributes)
 {
     IHTMLElement element;
     MarkupServices.CreateElement(tagID, attributes, out element);
     return element;
 }
        /// <summary>
        /// Returns the markup pointer to the position of the first exit scope of type tagId or type terminatingTagId which follows this markup range.
        /// Returns null if text exists between the range and such an exit scope, or if there is no such exit scope.
        /// </summary>
        /// <param name="terminatingTagId"></param>
        /// <returns></returns>
        internal MarkupPointer NextExitScopeWithoutInterveningText(MarkupRange selection, _ELEMENT_TAG_ID tagId, _ELEMENT_TAG_ID terminatingTagId, out bool primaryTagIdMatch)
        {
            MarkupContext context = new MarkupContext();

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

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

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

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

                        break;
                    case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope:
                    case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_NoScope:
                        break;
                    case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text:
                        return null;
                }
            }
        }
        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 IHTMLElement WrapRangeInSpanElement(_ELEMENT_TAG_ID tagId, string attributes, MarkupRange spanRange)
        {
            MarkupRange insertionRange = _markupServices.CreateMarkupRange();
            IHTMLElement newSpanElement = _markupServices.CreateElement(tagId, attributes);

            //insert the new span element in front of the span content
            insertionRange.Start.MoveToPointer(spanRange.Start);
            insertionRange.End.MoveToPointer(spanRange.Start);
            _markupServices.InsertElement(newSpanElement, insertionRange.Start, insertionRange.End);

            //move the span content inside the new span element
            insertionRange.Start.MoveAdjacentToElement(newSpanElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin);
            spanRange.Start.MoveAdjacentToElement(newSpanElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd);

            _markupServices.Move(spanRange.Start, spanRange.End, insertionRange.Start);
            return newSpanElement;
        }
 private MarkupRange ApplyInlineTagToBlockFreeSelection(_ELEMENT_TAG_ID tagId, string attributes, MarkupRange blockFreeSelection)
 {
     // @RIBBON TODO: May want to be a bit more sophisticated and eliminate redundant tags
     return _markupServices.CreateMarkupRange(WrapRangeInSpanElement(tagId, attributes, blockFreeSelection));
 }
        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 SemanticHtmlGalleryItem(string elementName, _ELEMENT_TAG_ID elementTagId, string label, Bitmap bitmap)
     : base(label, bitmap, label)
 {
     this.elementName  = elementName;
     this.elementTagId = elementTagId;
 }
 public static void ApplyBlockStyle(HtmlEditorControl editor, _ELEMENT_TAG_ID styleTagId, MarkupRange selection, MarkupRange maximumBounds, MarkupRange postOpSelection)
 {
     new HtmlBlockFormatHelper(editor).ApplyBlockStyle(styleTagId, selection, maximumBounds, postOpSelection);
 }
 /// <summary>
 /// Returns the tag name given the identifier (ID).
 /// </summary>
 /// <param name="e"></param>
 /// <returns></returns>
 public string GetNameForTagId(_ELEMENT_TAG_ID tagId)
 {
     IntPtr p;
     MarkupServices.GetNameForTagID(tagId, out p);
     return Marshal.PtrToStringBSTR(p);
 }
        void IHtmlEditorCommandSource.ClearFormatting()
        {
            if (_initialDocumentLoaded)
            {
                MarkupRange selectedMarkupRange = SelectedMarkupRange;
                if (IsValidContentInsertionPoint(selectedMarkupRange))
                {
                    using (IUndoUnit undo = CreateUndoUnit())
                    {
                        MarkupRange selection = SelectedMarkupRange;
                        using (DamageServices.CreateDamageTracker(selection, true))
                        {
                            try
                            {
                                // Note: that if the selection is non-empty, the mshtml command REMOVEFORMAT applies to word level.
                                GetMshtmlCommand(IDM.REMOVEFORMAT).Execute();

                                // REMOVEFORMAT does not remove :h1, h2, h3, h4, h5, h6, ul, ol, li.
                                // We have to remove these ourselves.
                                // First, we change h1, h2, h3, h4, h5, h6, and li to p
                                // Then we remove ul and ol.

                                // Any list items should now be paragraph elements
                                _ELEMENT_TAG_ID[] toBeParagraph = new _ELEMENT_TAG_ID[] { _ELEMENT_TAG_ID.TAGID_LI,
                                                                                      _ELEMENT_TAG_ID.TAGID_H1,
                                                                                      _ELEMENT_TAG_ID.TAGID_H2,
                                                                                      _ELEMENT_TAG_ID.TAGID_H3,
                                                                                      _ELEMENT_TAG_ID.TAGID_H4,
                                                                                      _ELEMENT_TAG_ID.TAGID_H5,
                                                                                      _ELEMENT_TAG_ID.TAGID_H6,
                                                                                    };
                                if (!IsEditFieldSelected)
                                {
                                    HtmlStyleHelper.ChangeElementTagIds(MarkupServices, selection, toBeParagraph, _ELEMENT_TAG_ID.TAGID_P);

                                    MarkupRange parentBlockRange = MarkupServices.CreateMarkupRange(selection.ParentBlockElement());
                                    foreach (_ELEMENT_TAG_ID tagId in new[] {_ELEMENT_TAG_ID.TAGID_UL,
                                                                     _ELEMENT_TAG_ID.TAGID_OL,
                                                                     _ELEMENT_TAG_ID.TAGID_BLOCKQUOTE})
                                    {
                                        parentBlockRange.RemoveElementsByTagId(tagId, false);
                                    }

                                    // We'll remove the alignment by removing the align attribute at block level
                                    HtmlStyleHelper.RemoveAttributes(MarkupServices, parentBlockRange, new[] { "align" });
                                }

                                //reselect the selected text.
                                if (selection.IsEmpty())
                                {
                                    DisplayServices.TraceMoveToMarkupPointer(CaretPositionDisplayPointer, selection.Start);
                                    SynchronizeCaretWithDisplayPointer(CaretPositionDisplayPointer, true);
                                }
                                else
                                    selection.ToTextRange().select();

                            }
                            catch (Exception ex)
                            {
                                Trace.Fail("Exception thrown during ClearFormatting: " + ex);
                            }
                        }

                        undo.Commit();
                    }
                }
            }
        }
        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 HtmlElementFormattingStyle(string name, string element, _ELEMENT_TAG_ID elementTagId)
 {
     _name         = name;
     _element      = element;
     _elementTagId = elementTagId;
 }
        public static IHTMLElement WrapRangeInElement(MshtmlMarkupServices services, MarkupRange range, _ELEMENT_TAG_ID tagId, string attributes)
        {
            IHTMLElement newElement = services.CreateElement(tagId, attributes);

            services.InsertElement(newElement, range.Start, range.End);

            return(newElement);
        }
        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();
            }
        }
 private bool IsSelection(_ELEMENT_TAG_ID tagId)
 {
     if (_initialDocumentLoaded)
     {
         return SelectedMarkupRange.IsTagId(tagId, true);
     }
     return false;
 }
        public void RemoveElementsByTagId(_ELEMENT_TAG_ID tagId, bool onlyIfNoAttributes)
        {
            if (tagId == _ELEMENT_TAG_ID.TAGID_NULL)
                return;

            // Remove the tagId up the parent chain
            IHTMLElement currentElement = ParentElement();
            while (currentElement != null)
            {
                if (MarkupServices.GetElementTagId(currentElement) == tagId &&
                    (!onlyIfNoAttributes || !HTMLElementHelper.HasMeaningfulAttributes(currentElement)))
                {
                    try
                    {
                        MarkupServices.RemoveElement(currentElement);
                    }
                    catch (COMException e)
                    {
                        Trace.Fail(String.Format("Failed to remove element ({0}) with error: {1}",
                            currentElement.outerHTML,   // {0}
                            e                           // {1}
                        ));
                    }
                }
                currentElement = currentElement.parentElement;
            }

            // Remove any other instances
            IHTMLElement[] elements =
                GetElements(ElementFilters.CreateTagIdFilter(MarkupServices.GetNameForTagId(tagId)), false);
            foreach (IHTMLElement e in elements)
            {
                if (MarkupServices.GetElementTagId(e) == tagId &&
                    (!onlyIfNoAttributes || !HTMLElementHelper.HasMeaningfulAttributes(e)))
                {
                    try
                    {
                        MarkupServices.RemoveElement(e);
                    }
                    catch (COMException ex)
                    {
                        Trace.Fail(String.Format("Failed to remove element ({0}) with error: {1}",
                            e.outerHTML,   // {0}
                            ex             // {1}
                        ));
                    }
                }
            }
        }
        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 HtmlElementFormattingStyle(string name, string element, _ELEMENT_TAG_ID elementTagId)
 {
     _name = name;
     _element = element;
     _elementTagId = elementTagId;
 }
        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);
            }
        }
Example #40
0
 public static void ApplyBlockStyle(HtmlEditorControl editor, _ELEMENT_TAG_ID styleTagId, MarkupRange selection, MarkupRange maximumBounds, MarkupRange postOpSelection)
 {
     new HtmlBlockFormatHelper(editor).ApplyBlockStyle(styleTagId, selection, maximumBounds, postOpSelection);
 }
        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));
        }
 public static IHTMLElement WrapRangeInElement(MshtmlMarkupServices services, MarkupRange range, _ELEMENT_TAG_ID tagId)
 {
     return WrapRangeInElement(services, range, tagId, string.Empty);
 }
 public static IHTMLElement WrapRangeInElement(MshtmlMarkupServices services, MarkupRange range, _ELEMENT_TAG_ID tagId)
 {
     return(WrapRangeInElement(services, range, tagId, string.Empty));
 }
        public static IHTMLElement WrapRangeInElement(MshtmlMarkupServices services, MarkupRange range, _ELEMENT_TAG_ID tagId, string attributes)
        {
            IHTMLElement newElement = services.CreateElement(tagId, attributes);

            services.InsertElement(newElement, range.Start, range.End);

            return newElement;
        }
        /// <summary>
        /// Determines if a range has a particular _ELEMENT_TAG_ID applied.
        /// </summary>
        /// <param name="tagId"></param>
        /// <param name="partially">If true, then IsTagId will return true if any part of it is contained within a tagId element.
        ///                         If false, then IsTagId will return true only if the range is entirely contained within a tagId element.</param>
        /// <returns></returns>
        public bool IsTagId(_ELEMENT_TAG_ID tagId, bool partially)
        {
            // This first block of code will return true if the range is entirely contained within an element with the given tagId.
            IHTMLElement currentElement = ParentElement();
            while (currentElement != null)
            {
                if (MarkupServices.GetElementTagId(currentElement) == tagId)
                    return true;

                currentElement = currentElement.parentElement;
            }

            // This second block of code will return true if the range is partially contained within an element with the given tagId.
            if (partially)
            {
                IHTMLElement[] elements = GetElements(ElementFilters.CreateTagIdFilter(MarkupServices.GetNameForTagId(tagId)), false);
                return elements.Length > 0;
            }

            return false;
        }
        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);
        }