/// <summary> /// Fixes up all the headers in the entire markupRange. /// </summary> /// <param name="turnBold">Whether or not the text should be turning bold.</param> private void FixupHeaders(bool turnBold) { IHTMLElement elementStartHeader = markupRange.Start.GetParentElement(ElementFilters.HEADER_ELEMENTS); IHTMLElement elementEndHeader = markupRange.End.GetParentElement(ElementFilters.HEADER_ELEMENTS); MarkupRange currentRange = markupRange.Clone(); if (elementStartHeader != null) { // Takes care of the following cases: // <h1>...|blah|...</h1> // <h1>...|blah...</h1>...|... MarkupRange startRange = markupServices.CreateMarkupRange(elementStartHeader, false); startRange.Start.MoveToPointer(markupRange.Start); if (startRange.End.IsRightOf(markupRange.End)) { startRange.End.MoveToPointer(markupRange.End); } FixupHeaderRange(startRange, turnBold); currentRange.Start.MoveAdjacentToElement(elementStartHeader, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); if (currentRange.End.IsLeftOf(currentRange.Start)) { currentRange.End.MoveToPointer(currentRange.Start); } } if (elementEndHeader != null && !HTMLElementHelper.ElementsAreEqual(elementStartHeader, elementEndHeader)) { // Takes care of the following case: // ...|...<h1>...blah|...</h1> MarkupRange endRange = markupServices.CreateMarkupRange(elementEndHeader, false); endRange.End.MoveToPointer(markupRange.End); FixupHeaderRange(endRange, turnBold); currentRange.End.MoveAdjacentToElement(elementEndHeader, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin); if (currentRange.Start.IsRightOf(currentRange.End)) { currentRange.Start.MoveToPointer(currentRange.End); } } if (!markupRange.InRange(currentRange)) { return; } IHTMLElement[] headerElements = currentRange.GetElements(ElementFilters.HEADER_ELEMENTS, true); if (headerElements != null && headerElements.Length > 0) { foreach (IHTMLElement element in headerElements) { MarkupRange headerRange = markupServices.CreateMarkupRange(element, false); FixupHeaderRange(headerRange, turnBold); } } }
/// <summary> /// Creates a markup range that will cling to the smart content element. /// </summary> /// <returns></returns> private MarkupRange CreateElementClingMarkupRange() { MarkupRange markupRange = _markupServices.CreateMarkupRange(HTMLElement); markupRange.Start.Cling = true; markupRange.End.Cling = true; markupRange.Start.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Right; markupRange.End.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Left; return(markupRange); }
private string GrowToAnchorParent(HTMLData htmlData) { if (htmlData.OnlyImageElement == null) { return(null); } string html; // Load up the html document from the clipboard to a document to examine the html about to be inserted MshtmlMarkupServices markupServices = new MshtmlMarkupServices(htmlData.HTMLDocument as IMarkupServicesRaw); MarkupRange range = markupServices.CreateMarkupRange(htmlData.OnlyImageElement, true); // look to see if this is a case where the inserted html is <a>|<img>|</a> MarkupContext markupContextStart = range.Start.Left(true); MarkupContext markupContextEnd = range.End.Right(true); // if that is the cause, change the html about to be inserted to |<a><img></a>| if (markupContextStart.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope && markupContextEnd.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope && markupContextStart.Element.tagName == "A" && markupContextEnd.Element.tagName == "A") { html = markupContextStart.Element.outerHTML; } else { html = htmlData.HTMLSelection; } return(html); }
private void UpdateImageLink(string href, IHTMLElement ImgElement, ILinkOptions defaultOptions) { MshtmlMarkupServices markupServices = new MshtmlMarkupServices((IMarkupServicesRaw)ImgElement.document); IHTMLElement parentElement = ImgElement.parentElement; if (!(parentElement is IHTMLAnchorElement)) { parentElement = markupServices.CreateElement(_ELEMENT_TAG_ID.TAGID_A, null); MarkupRange range = markupServices.CreateMarkupRange(); range.MoveToElement(ImgElement, true); markupServices.InsertElement(parentElement, range.Start, range.End); //set the default target attribute for the new element string target = defaultOptions.ShowInNewWindow ? "_blank" : null; IHTMLAnchorElement htmlAnchorElement = (parentElement as IHTMLAnchorElement); if (htmlAnchorElement.target != target) //don't set the target to null if its already null (avoids adding empty target attr) { htmlAnchorElement.target = target; } ImageViewer viewer = DhtmlImageViewers.GetImageViewer(DhtmlImageViewer); if (viewer != null) { if (defaultOptions.UseImageViewer) { viewer.Apply(htmlAnchorElement, defaultOptions.ImageViewerGroupName); } } } parentElement.setAttribute("href", href, 0); }
/// <summary> /// Initialize word range for the specified markup-range within the document /// </summary> public MshtmlWordRange(IHTMLDocument document, bool useDocumentSelectionRange, MarkupRangeFilter filter, DamageFunction damageFunction) { MshtmlMarkupServices markupServices = new MshtmlMarkupServices((IMarkupServicesRaw)document); IHTMLDocument2 document2 = (IHTMLDocument2)document; MarkupRange markupRange; if (useDocumentSelectionRange) { markupRange = markupServices.CreateMarkupRange(document2.selection); } else { // TODO: Although this works fine, it would be better to only spellcheck inside editable regions. markupRange = markupServices.CreateMarkupRange(document2.body, false); } Init(document, markupServices, markupRange, filter, damageFunction, useDocumentSelectionRange); }
private static void PrintHtml(HtmlWriter writer, MshtmlMarkupServices MarkupServices, MarkupRange bounds) { //create a range to span a single position while walking the doc MarkupRange range = MarkupServices.CreateMarkupRange(); range.Start.MoveToPointer(bounds.Start); range.End.MoveToPointer(bounds.Start); //create a context that can be reused while walking the document. MarkupContext context = new MarkupContext(); //move the range.End to the right and print out each element along the way range.End.Right(true, context); while (context.Context != _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_None && range.Start.IsLeftOf(bounds.End)) { string text = null; if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_Text) { //if this is a text context, then get the text that is between the start and end points. text = range.HtmlText; //the range.HtmlText operation sometimes returns the outer tags for a text node, //so we need to strip the tags. //FIXME: if the Right/Left operations returned the available text value, this wouldn't be necessary. if (text != null) { text = StripSurroundingTags(text); } } else if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope) { string htmlText = range.HtmlText; if (context.Element.innerHTML == null && htmlText != null && htmlText.IndexOf(" ") != -1) { //HACK: Under these conditions, there was a was an invisible NBSP char in the //document that is not detectable by walking through the document with MarkupServices. //So, we force the text of the element to be the char to ensure that the //whitespace that was visible in the editor is visible in the final document. text = " "; } } //print the context. printContext(writer, context, text, range); //move the start element to the spot where the end currently is so tht there is //only ever a single difference in position range.Start.MoveToPointer(range.End); //move the end to the next position range.End.Right(true, context); } }
protected ContentSelection(IHtmlEditorComponentContext editorComponentContext, IHTMLElement element, SmartContentState contentState) { _editorComponentContext = editorComponentContext; _markupServices = editorComponentContext.MarkupServices; _element = element; _contentState = contentState; _markupRange = _markupServices.CreateMarkupRange(_element, true); _markupRange.Start.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Right; _markupRange.End.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Left; _markupRange.Start.Cling = false; _markupRange.End.Cling = false; }
public virtual string GetEditedHtml(bool useXhtml, bool doCleanup) { try { if (doCleanup || useXhtml) { MshtmlMarkupServices markupServices = new MshtmlMarkupServices(HTMLElement.document as IMarkupServicesRaw); if (doCleanup) { MarkupRange bodyRange = markupServices.CreateMarkupRange(((IHTMLDocument2)HTMLElement.document).body, false); bodyRange.RemoveElementsByTagId(_ELEMENT_TAG_ID.TAGID_FONT, true); } if (useXhtml) { MarkupRange bounds = markupServices.CreateMarkupRange(HTMLElement, false); string xhtml = FormattedHtmlPrinter.ToFormattedHtml(markupServices, bounds); return(doCleanup ? CleanupHtml(xhtml, true) : xhtml); } } } catch (Exception e) { // E.g. this failure case: <pre><b></pre></b> Trace.Fail("Exception generating XHTML: " + e.ToString()); } string html = HTMLElement.innerHTML ?? String.Empty; if (doCleanup) { return(CleanupHtml(html, false)); } else { return(html); } }
/// <summary> /// Searches through the provided document for a start and end comment marker and then returns the fragment as /// a MarkupRange. /// </summary> /// <param name="document">The document to search.</param> /// <param name="startMarker">The comment text that marks the start of the fragment /// (e.g. <!--StartFragment--> ).</param> /// <param name="endMarker">The comment text that marks the end of the fragment /// (e.g. <!--EndFragment--> ).</param> /// <returns>The fragment as a MarkupRange or null if no valid fragment was found.</returns> private MarkupRange FindMarkedFragment(IHTMLDocument2 document, string startMarker, string endMarker) { MarkupPointer startFragment = null; MarkupPointer endFragment = null; MshtmlMarkupServices markupServices = new MshtmlMarkupServices((IMarkupServicesRaw)document); // Look for the markers in the document. foreach (IHTMLElement element in document.all) { if (element is IHTMLCommentElement && ((IHTMLCommentElement)element).text == startMarker) { startFragment = markupServices.CreateMarkupPointer(element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); } else if (element is IHTMLCommentElement && ((IHTMLCommentElement)element).text == endMarker) { endFragment = markupServices.CreateMarkupPointer(element, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin); } } if (startFragment == null || endFragment == null || !startFragment.Positioned || !endFragment.Positioned || startFragment.IsRightOf(endFragment)) { Trace.WriteLine("Unable to find fragment or invalid fragment!"); return(null); } // WinLive 251786: IE (and most other browsers) allow HTML like the following: // <p>This is a paragraph[cursor] // <p>This is a paragraph // However, when we use MarkupPointers to walk through this HTML, IE pretends there is a </p> at the end // of each of the above lines. This can cause issues when we copy part of this HTML somewhere else (e.g // everything after the [cursor]) and attempt to walk through both copies (e.g. during paste with keep // source formatting) at the same time. This holds true for some other elements, such as <li>s and <td>s. MarkupContext startContext = startFragment.Right(false); if (startFragment.IsLeftOf(endFragment) && startContext.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope && startContext.Element != null && ElementFilters.IsEndTagOptional(startContext.Element) && !Regex.IsMatch(startContext.Element.outerHTML, String.Format(CultureInfo.InvariantCulture, @"</{0}(\s[^>]*)?>\s*$", startContext.Element.tagName), RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)) { startFragment.Right(true); } return(markupServices.CreateMarkupRange(startFragment, endFragment)); }
/// <summary> /// Disambiguates a set of title regions to determine which should be editable based on proximity to the main post body element. /// </summary> /// <param name="bodyElement"></param> /// <param name="doc"></param> /// <param name="titleElements"></param> /// <returns>The title region in closest proximity to the post body element.</returns> protected static IHTMLElement GetPrimaryEditableTitleElement(IHTMLElement bodyElement, IHTMLDocument doc, IHTMLElement[] titleElements) { IHTMLDocument2 doc2 = (IHTMLDocument2)doc; IHTMLElement titleElement = titleElements[0]; if (titleElements.Length > 1) { try { MshtmlMarkupServices markupServices = new MshtmlMarkupServices((IMarkupServicesRaw)doc2); MarkupRange bodyRange = markupServices.CreateMarkupRange(bodyElement, true); MarkupPointer titlePointer = null; MarkupPointer tempPointer = markupServices.CreateMarkupPointer(); foreach (IHTMLElement title in titleElements) { tempPointer.MoveAdjacentToElement(title, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin); if (titlePointer == null) { titlePointer = markupServices.CreateMarkupPointer(title, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin); } else { tempPointer.MoveAdjacentToElement(title, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin); if (tempPointer.IsLeftOf(bodyRange.End) && tempPointer.IsRightOf(titlePointer)) { //the temp pointer is closer to the body element, so assume it is more appropriate //to use as the title. titleElement = title; titlePointer.MoveToPointer(tempPointer); } } } } catch (COMException ex) { Trace.WriteLine("Failed to differentiate between multiple nodes with title text, using the first node. Exception: " + ex); } catch (InvalidCastException ex) { Trace.WriteLine("Failed to differentiate between multiple nodes with title text, using the first node. Exception: " + ex); } } return(titleElement); }
/// <summary> /// Creates a MarkupRange that contains the entire provided document. /// </summary> /// <param name="document">The document to select.</param> /// <returns>A MarkupRange that contains the entire document.</returns> private MarkupRange SelectAll(IHTMLDocument2 document) { MshtmlMarkupServices markupServices = new MshtmlMarkupServices((IMarkupServicesRaw)document); MarkupRange entireDocument = markupServices.CreateMarkupRange(((IHTMLDocument3)document).documentElement, true); // Make sure the doctype and anything else outside the root element is selected too. MarkupContext context = entireDocument.Start.Left(true); while (context.Context != _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_None) { context = entireDocument.Start.Left(true); } context = entireDocument.End.Right(true); while (context.Context != _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_None) { context = entireDocument.End.Right(true); } return(entireDocument); }
public MisspelledWordInfo FindSegment(MshtmlMarkupServices markupServices, IMarkupPointerRaw current) { //binary search int start = 0; int end = list.Count - 1; int i = Middle(start, end); while (-1 != i) { SegmentDef x = (SegmentDef)list.GetByIndex(i); bool startTest; current.IsRightOfOrEqualTo(x.startPtr, out startTest); if (startTest) { bool endTest; current.IsLeftOfOrEqualTo(x.endPtr, out endTest); if (endTest) { MarkupPointer pStart = markupServices.CreateMarkupPointer(x.startPtr); MarkupPointer pEnd = markupServices.CreateMarkupPointer(x.endPtr); MarkupRange range = markupServices.CreateMarkupRange(pStart, pEnd); //this could be a "phantom" range...no more content due to uncommitted damage or other reasons //if it is phantom, remove it from the tracker and return null if (range.Text == null) { list.RemoveAt(i); return(null); } return(new MisspelledWordInfo(range, x.word)); } start = i + 1; } else { end = i - 1; } i = Middle(start, end); } return(null); }
protected MarkupRange GetMarkupRange() { MarkupRange range = null; try { if (_markupContainer != null) { range = _markupServices.CreateMarkupRange(); IMarkupPointer2Raw pointer2StartRaw = range.Start.PointerRaw as IMarkupPointer2Raw; IMarkupPointer2Raw pointer2EndRaw = range.End.PointerRaw as IMarkupPointer2Raw; pointer2StartRaw.MoveToMarkupPosition(_markupContainer, _startPosition); pointer2EndRaw.MoveToMarkupPosition(_markupContainer, _endPosition); } } catch (Exception e) { Debug.Fail("Failed to get markup range", e.ToString()); } return(range); }
public static void InsertContentIntoElement(string content, ISmartContent sContent, IContentSourceSidebarContext contentSourceContext, IHTMLElement element) { MshtmlMarkupServices MarkupServices = new MshtmlMarkupServices((IMarkupServicesRaw)element.document); //Note: undo/redo disabled for smart content since undo causes the HTML to get out of sync //with the inserter's settings state, so undo changes will be blown away the next time the //the inserter's HTML is regenerated. Also note that making this insertion without wrapping it //in an undo clears the undo/redo stack, which is what we want for beta. //string undoId = Guid.NewGuid().ToString(); MarkupRange htmlRange = MarkupServices.CreateMarkupRange(element, false); htmlRange.Start.PushCling(true); htmlRange.End.PushCling(true); MarkupServices.Remove(htmlRange.Start, htmlRange.End); htmlRange.Start.PopCling(); htmlRange.End.PopCling(); element.style.padding = ToPaddingString(sContent.Layout); if (sContent.Layout.Alignment == Alignment.None || sContent.Layout.Alignment == Alignment.Right || sContent.Layout.Alignment == Alignment.Left) { element.style.display = "inline"; element.style.marginLeft = "0px"; element.style.marginRight = "0px"; element.style.styleFloat = sContent.Layout.Alignment.ToString().ToLower(CultureInfo.InvariantCulture); } else if (sContent.Layout.Alignment == Alignment.Center) { element.style.styleFloat = Alignment.None.ToString().ToLower(CultureInfo.InvariantCulture); element.style.display = "block"; element.style.marginLeft = "auto"; element.style.marginRight = "auto"; } // Clear out any width on the overall smart content block, if the element is centered, we will add the width back in later // after we calcuate it from the childern, the current width value is stale. element.style.width = ""; //Note: we use MarkupServices to insert the content so that IE doesn't try to fix up URLs. //Element.insertAdjacentHTML() is a no-no because it rewrites relaive URLs to include //the fullpath from the local filesytem. //MarkupServices.ParseString() doesn't attempt to fix up URLs, so its safe to use. //We will now stage the new content into a MarkupContainer, and then move it into //the working document. MarkupPointer sc1 = MarkupServices.CreateMarkupPointer(); MarkupPointer sc2 = MarkupServices.CreateMarkupPointer(); //Create a temporary document from the html and set the start/end pointers to the //start and end of the document. MarkupServices.ParseString(content, sc1, sc2); IHTMLDocument2 doc = sc1.GetDocument(); MarkupRange stagingRange = MarkupServices.CreateMarkupRange(sc1, sc2); stagingRange.MoveToElement(doc.body, false); //IE7 hack: fixes bug 305512. Note that this will destroy the inner content of the element, //so make sure it is called before the refreshed content is inserted. BeforeInsertInvalidateHackForIE7(element); //move the content from the staging area into the actual insertion point. MarkupServices.Move(stagingRange.Start, stagingRange.End, htmlRange.End); if (sContent.Layout.Alignment == Alignment.Center) { MarkupContext mc = htmlRange.End.Right(false); MarkupRange range = MarkupServices.CreateMarkupRange(mc.Element, false); IHTMLElement[] childern = range.GetTopLevelElements(MarkupRange.FilterNone); int maxWidth = 0; foreach (IHTMLElement child in childern) { maxWidth = Math.Max(maxWidth, child.offsetWidth); } if (maxWidth != 0) { mc.Element.style.width = maxWidth; } } // Let the context provider know the smart content was edited. string contentSourceId, contentId; ContentSourceManager.ParseContainingElementId(element.id, out contentSourceId, out contentId); contentSourceContext.OnSmartContentEdited(contentId); }
public static void ChangeElementTagIds(MshtmlMarkupServices markupServices, MarkupRange selection, _ELEMENT_TAG_ID[] tagBefore, _ELEMENT_TAG_ID tagAfter) { HtmlStyleHelper htmlStyleHelper = new HtmlStyleHelper(markupServices); int parentStartDiff = 0; MarkupRange rangeToChange; bool selectionStartedEmpty = selection.IsEmpty(); if (selectionStartedEmpty) { // Operate on parent block element rangeToChange = markupServices.CreateMarkupRange(selection.ParentBlockElement()); parentStartDiff = selection.Start.MarkupPosition - rangeToChange.Start.MarkupPosition; } else { rangeToChange = selection; // If expanding the selection would not include any new text, then expand it. // <h1>|abc|</h1> --> |<h1>abc</h1>| rangeToChange.MoveOutwardIfNoText(); } IHTMLElementFilter[] filters = new IHTMLElementFilter[tagBefore.Length]; for (int i = 0; i < tagBefore.Length; i++) { filters[i] = ElementFilters.CreateTagIdFilter(markupServices.GetNameForTagId(tagBefore[i])); } IHTMLElement[] elements = rangeToChange.GetElements(ElementFilters.CreateCompoundElementFilter(filters), false); foreach (IHTMLElement element in elements) { MarkupRange elementRange = markupServices.CreateMarkupRange(element); int startPositionDiff = rangeToChange.Start.MarkupPosition - elementRange.Start.MarkupPosition; int endPositionDiff = rangeToChange.End.MarkupPosition - elementRange.End.MarkupPosition; // @RIBBON TODO: Appropriately preserve element attributes when changing tag ids? MarkupRange newElementRange = markupServices.CreateMarkupRange(htmlStyleHelper.WrapRangeInSpanElement(tagAfter, null, elementRange)); markupServices.RemoveElement(element); MarkupPointer startPointer = rangeToChange.Start.Clone(); startPointer.MoveToMarkupPosition(startPointer.Container, newElementRange.Start.MarkupPosition + startPositionDiff); if (startPointer.IsLeftOf(rangeToChange.Start)) { rangeToChange.Start.MoveToPointer(startPointer); } MarkupPointer endPointer = rangeToChange.End.Clone(); endPointer.MoveToMarkupPosition(endPointer.Container, newElementRange.End.MarkupPosition + endPositionDiff); if (endPointer.IsLeftOf(elementRange.End)) { rangeToChange.End.MoveToPointer(endPointer); } } if (selectionStartedEmpty) { selection.Start.MoveToMarkupPosition(selection.Start.Container, rangeToChange.Start.MarkupPosition + parentStartDiff); selection.Collapse(true); } }
public static MarkupRange ApplyInlineTag(MshtmlMarkupServices markupServices, _ELEMENT_TAG_ID tagId, string attributes, MarkupRange selection, bool toggle) { HtmlStyleHelper htmlStyleHelper = new HtmlStyleHelper(markupServices); // Aligning the with the behavior of Word, we will make <SUP> and <SUB> mutually exclusive. // That is, if you are applying <SUB> to a selection that has <SUP> applied already, we will first remove the <SUP>, and vice versa. // Wait, if empty and we're on the very end of the already existing formatting, then we just want to jump out and apply... MarkupRange selectionToApply = selection.Clone(); if (toggle) { // If already entirely inside the tag // If empty and just inside of the closing tag, then jump outside the closing tag // Else remove the tag // If already entirely outside the tag // If empty, apply the tag and put selection inside // If non-empty, then apply tag and reselect // If partially inside the tag // Remove the tag _ELEMENT_TAG_ID mutuallyExclusiveTagId = _ELEMENT_TAG_ID.TAGID_NULL; switch (tagId) { case _ELEMENT_TAG_ID.TAGID_SUP: mutuallyExclusiveTagId = _ELEMENT_TAG_ID.TAGID_SUB; break; case _ELEMENT_TAG_ID.TAGID_SUB: mutuallyExclusiveTagId = _ELEMENT_TAG_ID.TAGID_SUP; break; default: break; } if (selection.IsEmpty()) { // If the selection is empty and we're just inside the tagId closing tag (meaning that there is no text before the closing tag), // then we just hop outside of the tagId closing tag. bool exitScopeMatchesTagIdToBeApplied; MarkupPointer pointerOutsideTagIdScope = htmlStyleHelper.NextExitScopeWithoutInterveningText(selection, tagId, mutuallyExclusiveTagId, out exitScopeMatchesTagIdToBeApplied); if (pointerOutsideTagIdScope != null) { selectionToApply = markupServices.CreateMarkupRange(pointerOutsideTagIdScope, pointerOutsideTagIdScope); if (exitScopeMatchesTagIdToBeApplied) { return(selectionToApply); } // else we still need to apply tagId } } // If a mutually exclusive tag is applied, then remove it. if (selectionToApply.IsTagId(mutuallyExclusiveTagId, true)) { selectionToApply.RemoveElementsByTagId(mutuallyExclusiveTagId, false); } // If this tag is already applied, then remove it and return. if (selectionToApply.IsTagId(tagId, true)) { selectionToApply.RemoveElementsByTagId(tagId, false); return(selectionToApply); } } return(htmlStyleHelper.ApplyInlineTag(tagId, attributes, selectionToApply)); }
private MarkupRange ApplyInlineTag(_ELEMENT_TAG_ID tagId, string attributes, MarkupRange selection) { MarkupRange newSelection = _markupServices.CreateMarkupRange(); // If the selection is empty, then just insert the tag if (selection.IsEmpty()) { newSelection.MoveToElement(WrapRangeInSpanElement(tagId, attributes, selection), false); return(newSelection); } // Start at the beginning of the selection move forward until you hit a block start/exit context or the end of the selection bool keepApplying = true; MarkupContext contextStart = new MarkupContext(); MarkupRange blockFreeRange = _markupServices.CreateMarkupRange(selection.Start.Clone(), selection.Start.Clone()); MarkupPointer currentPointer = _markupServices.CreateMarkupPointer(blockFreeRange.Start); while (keepApplying) { // Check if moving right would be beyond the bounds of the selection. if (currentPointer.IsRightOfOrEqualTo(selection.End)) { // We've hit the end of the selection, so we're done. keepApplying = false; Debug.Assert(blockFreeRange.Start.IsLeftOfOrEqualTo(selection.End)); blockFreeRange.End.MoveToPointer(selection.End.IsLeftOf(currentPointer) ? selection.End : currentPointer); if (ShouldApplyInlineTagToBlockFreeSelection(blockFreeRange)) { newSelection.ExpandToInclude(ApplyInlineTagToBlockFreeSelection(tagId, attributes, blockFreeRange)); } break; } // Check if the next context is entering or exiting a block. currentPointer.Right(false, contextStart); if (contextStart.Element != null && ElementFilters.IsBlockElement(contextStart.Element)) { switch (contextStart.Context) { case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope: case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope: { blockFreeRange.End.MoveToPointer(selection.End.IsLeftOf(currentPointer) ? selection.End : currentPointer); if (ShouldApplyInlineTagToBlockFreeSelection(blockFreeRange)) { newSelection.ExpandToInclude(ApplyInlineTagToBlockFreeSelection(tagId, attributes, blockFreeRange)); } if (contextStart.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope) { blockFreeRange.Start.MoveAdjacentToElement(contextStart.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin); } else if (contextStart.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope) { blockFreeRange.Start.MoveAdjacentToElement(contextStart.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); } blockFreeRange.Collapse(true); } break; case _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_None: { keepApplying = false; blockFreeRange.End.MoveToPointer(selection.End.IsLeftOf(currentPointer) ? selection.End : currentPointer); if (ShouldApplyInlineTagToBlockFreeSelection(blockFreeRange)) { newSelection.ExpandToInclude(ApplyInlineTagToBlockFreeSelection(tagId, attributes, blockFreeRange)); } } break; default: break; } } // Finally, move our pointer currentPointer.Right(true); } if (newSelection.Positioned) { newSelection.Trim(); } return(newSelection); }
/// <summary> /// Grabs HTML copied in the clipboard and pastes it into the document (pulls in a copy of embedded content too) /// </summary> protected override bool DoInsertData(DataAction action, MarkupPointer begin, MarkupPointer end) { using (new WaitCursor()) { try { string baseUrl = UrlHelper.GetBasePathUrl(DataMeister.HTMLData.SourceURL); string html = DataMeister.HTMLData.HTMLSelection; //Check to see if the selection has an incomplete unordered list var finder = new IncompleteListFinder(html); finder.Parse(); if ((!EditorContext.CleanHtmlOnPaste) || finder.HasIncompleteList) { using (IUndoUnit undoUnit = EditorContext.CreateInvisibleUndoUnit()) { // Create a new MarkupContainer off of EditorContext's document that contains the source HTML // with comments marking the start and end selection. MarkupContainer sourceContainer = EditorContext.MarkupServices.ParseString(DataMeister.HTMLData.HTMLWithMarkers); // MSHTML's ParseString implementation clears all the attributes on the <body> element, so we // have to manually add them back in. CopyBodyAttributes(DataMeister.HTMLData.HTMLWithMarkers, sourceContainer.Document.body); MarkupRange sourceRange = FindMarkedFragment(sourceContainer.Document, HTMLDataObject.START_FRAGMENT_MARKER, HTMLDataObject.END_FRAGMENT_MARKER); MshtmlMarkupServices sourceContainerMarkupServices = new MshtmlMarkupServices((IMarkupServicesRaw)sourceContainer.Document); // Some applications may not add the correct fragment markers (e.g. copying from Fiddler from // the Web Sessions view). We'll just select the entire <body> of the clipboard in this case. if (sourceRange == null) { sourceRange = sourceContainerMarkupServices.CreateMarkupRange(sourceContainer.Document.body, false); } else { // Make sure that we don't try to copy just parts of a table/list. We need to include the // parent table/list. if (!EditorContext.CleanHtmlOnPaste) { ExpandToIncludeTables(sourceRange, sourceContainerMarkupServices); } ExpandToIncludeLists(sourceRange, sourceContainerMarkupServices); } if (sourceRange != null) { if (!EditorContext.CleanHtmlOnPaste) { // WinLive 273280: Alignment on a table acts like a float, which can throw off the layout of the rest of // the document. If there is nothing before or after the table, then we can safely remove the alignment. RemoveAlignmentIfSingleTable(sourceRange); // Serialize the source HTML to a string while keeping the source formatting. MarkupRange destinationRange = EditorContext.MarkupServices.CreateMarkupRange(begin.Clone(), end.Clone()); html = KeepSourceFormatting(sourceRange, destinationRange); } else { html = sourceRange.HtmlText; } } undoUnit.Commit(); } Trace.Assert(html != null, "Inline source CSS failed!"); } if (html == null) { html = DataMeister.HTMLData.HTMLSelection; } if (IsPasteFromSharedCanvas(DataMeister)) { if (action == DataAction.Copy) { // WinLive 96840 - Copying and pasting images within shared canvas should persist source // decorator settings. "wlCopySrcUrl" is inserted while copy/pasting within canvas. html = EditorContext.FixImageReferences(ImageCopyFixupHelper.FixupSourceUrlForCopy(html), DataMeister.HTMLData.SourceURL); } } else { html = EditorContext.FixImageReferences(html, DataMeister.HTMLData.SourceURL); HtmlCleanupRule cleanupRule = HtmlCleanupRule.Normal; if (IsOfficeHtml(DataMeister.HTMLData)) { cleanupRule = HtmlCleanupRule.PreserveTables; } // In Mail, we want to preserve the style of the html that is on the clipboard // Whereas in Writer we by default want to remove formatting so it looks like your blog theme if (EditorContext.CleanHtmlOnPaste) { // optionally cleanup the html html = EditorContext.HtmlGenerationService.CleanupHtml(html, baseUrl, cleanupRule); } else { html = HtmlCleaner.StripNamespacedTagsAndCommentsAndMarkupDirectives(html); } // standard fixups html = EditorContext.HtmlGenerationService.GenerateHtmlFromHtmlFragment(html, baseUrl); } // insert the content if (EditorContext.MarshalHtmlSupported) { EditorContext.InsertHtml(begin, end, html, DataMeister.HTMLData.SourceURL); } else if (EditorContext.MarshalTextSupported) { // This is called only in the case that we're attempting to marshal HTML, but only // text is supported. In this case, we should down convert to text and provide that. html = HTMLDocumentHelper.HTMLToPlainText(html); EditorContext.InsertHtml(begin, end, html, DataMeister.HTMLData.SourceURL); } else { Debug.Assert(false, "Html being inserted when text or html isn't supported."); } // Now select what was just inserted EditorContext.MarkupServices.CreateMarkupRange(begin, end).ToTextRange().select(); //place the caret at the end of the inserted content //EditorContext.MoveCaretToMarkupPointer(end, true); return(true); } catch (Exception e) { //bugfix 1696, put exceptions into the trace log. Trace.Fail("Exception while inserting HTML: " + e.Message, e.StackTrace); return(false); } } }