/// <summary> /// Utility for deleting a range of content while suppressing pointer cling. /// </summary> /// <param name="start"></param> /// <param name="end"></param> private void DeleteContentNoCling(MarkupPointer start, MarkupPointer end) { start.PushCling(false); end.PushCling(false); try { DeleteContent(start, end); } finally { start.PopCling(); end.PopCling(); } }
/// <summary> /// Inserts the extended entry break into the editor at the specified location. /// </summary> internal IHTMLElement InsertExtendedEntryBreak(MarkupPointer insertionPoint) { IHTMLElement entryBreakDiv = EditorContext.MarkupServices.CreateElement(_ELEMENT_TAG_ID.TAGID_DIV, null); IHTMLElement postBodyElement = HTMLElement; insertionPoint.PushCling(false); insertionPoint.PushGravity(_POINTER_GRAVITY.POINTER_GRAVITY_Right); try { //insert the entryBreak DIV into the beginning of the post body entryBreakDiv.id = EXTENDED_ENTRY_ID; entryBreakDiv.setAttribute("name", EXTENDED_ENTRY_ID, 0); MarkupRange markupRange = EditorContext.MarkupServices.CreateMarkupRange(); markupRange.MoveToElement(postBodyElement, false); markupRange.End.MoveToPointer(markupRange.Start); EditorContext.MarkupServices.InsertElement(entryBreakDiv, markupRange.Start, markupRange.End); //move all content that should stay above the extended entry line, above the entryBreakDiv //this effectively forces all open tags to be closed, and leaves the insertion point below //the extended entry line (with the pre-insert parent tree still intact. markupRange.Start.MoveAdjacentToElement(entryBreakDiv, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); markupRange.End.MoveToPointer(insertionPoint); MarkupPointer target = EditorContext.MarkupServices.CreateMarkupPointer(entryBreakDiv, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin); EditorContext.MarkupServices.Move(markupRange.Start, markupRange.End, target); } finally { insertionPoint.PopCling(); insertionPoint.PopGravity(); } return entryBreakDiv; }
protected virtual void InsertHtml(MarkupPointer start, MarkupPointer end, string html, string sourceUrl, bool allowBlockBreakout) { MarkupRange range = MarkupServices.CreateMarkupRange(start, end); if (!IsValidContentInsertionPoint(range)) { DisplayMessage.Show(MessageId.InvalidInsertionPoint); return; } Trace.Assert(start.Positioned && end.Positioned, string.Format(CultureInfo.InvariantCulture, "Invalid pointer being used for insert. start:({0}),end:({1})", start.Positioned, end.Positioned)); // begin undo unit IUndoUnit undoUnit = CreateUndoUnit(); start.PushCling(true); end.PushCling(true); using (undoUnit) { // Any changes to the way we remove the content in the destination may need to be changed in // KeepSourceFormatting.PasteSourceOverDestination as well! MarkupPointerMoveHelper.PerformImageBreakout(start); MarkupPointerMoveHelper.PerformImageBreakout(end); //if the start and endpoints are not equal, then we need to paste over the selection //so delete the selected region (which will collapse the pointers to now be equal. if (!start.IsEqualTo(end)) { //delete the selected content if (ContentIsDeletableForInsert(start, end)) { // CT: There is currently a case where we leave empty blocks behind // see bug 628054. This happens when the start and end markup pointers don't completely // contain the selected blocks, like: <p>|line1</p><p>line2|</p>. In this case, calling // deleteNoContentNoClient will leave you with <p>|</p><p>|</p>. The next line collapses // the end pointer back to the start point since that is where selection started. DeleteContentNoCling(start, end); end.MoveToPointer(start); } } if (!string.IsNullOrEmpty(html)) { //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(); // Do the work ahead of time to get an <p></P> ready to be inserted // doing this work after the insert this html was called with sometimes // causes mshtml to not paint things until they are moused over(embeds) // BUG: 624122, 622715 MarkupPointer mpStart = MarkupServices.CreateMarkupPointer(); MarkupPointer mpEnd = MarkupServices.CreateMarkupPointer(); // Make a temp document and load our ending html into it. MarkupServices.ParseString(CONTENT_BODY_PADDING, mpStart, mpEnd); //Create a temporary document from the html and set the start/end pointers to the //start and end of the document. MarkupServices.ParseString(html, sc1, sc2); IHTMLDocument2 doc = sc1.GetDocument(); MarkupRange stagingRange = MarkupServices.CreateMarkupRange(sc1, sc2); stagingRange.MoveToElement(doc.body, false); // We only need to insert the ending new line if there was a div or image added bool allowNewLineInsert = ShouldAllowNewLineInsert(html); Trace.Assert(stagingRange.Positioned && stagingRange.Start.Positioned && stagingRange.End.Positioned && sc1.Positioned && sc2.Positioned, String.Format(CultureInfo.InvariantCulture, "Staging document is not ready. stagingRange:({0}),stagingRange.Start:({1}),stagingRange.End:({2}),sc1:({3}),sc2:({4})", stagingRange.Positioned, stagingRange.Start.Positioned, stagingRange.End.Positioned, sc1.Positioned, sc2.Positioned)); try { // Any changes to the way we remove the content in the destination may need to be changed in // KeepSourceFormatting.PasteSourceOverDestination as well! bool emptyBlockRemoved; if (stagingRange.ContainsElements(ElementFilters.IsBlockOrTableElement)) { // if the destination is an empty block element then just overwrite it emptyBlockRemoved = OverwriteDestinationBlockIfEmpty(start, PrimaryEditableBounds); if (!emptyBlockRemoved && allowBlockBreakout) { // otherwise split the destination block or move outside of the block MarkupHelpers.SplitBlockForInsertionOrBreakout(MarkupServices, PrimaryEditableBounds, start); } end.MoveToPointer(start); } } catch (COMException ex) { Trace.WriteLine(String.Format(CultureInfo.InvariantCulture, "RemoveBlockOrTableElement Failed ({0},{1},{2},{4}): {3}", stagingRange.Start.Positioned, stagingRange.End.Positioned, end.Positioned, ex, start.Positioned)); throw; } InflateEmptyParagraphs(stagingRange); FixUpStickyBrs(stagingRange); if (HTMLDocumentHelper.IsQuirksMode(HTMLDocument)) { ForceTablesToInheritFontColor(stagingRange); } Trace.Assert(stagingRange.Positioned && stagingRange.Start.Positioned && stagingRange.End.Positioned && sc1.Positioned && sc2.Positioned, String.Format(CultureInfo.InvariantCulture, "Staging document corrupt after RemoveBlockOrTableElement. stagingRange:({0}),stagingRange.Start:({1}),stagingRange.End:({2}),sc1:({3}),sc2:({4})", stagingRange.Positioned, stagingRange.Start.Positioned, stagingRange.End.Positioned, sc1.Positioned, sc2.Positioned)); IDisposable damageTracker = null; try { damageTracker = CreateDamageTracking(end, true); } catch (COMException ex) { Trace.WriteLine(String.Format(CultureInfo.InvariantCulture, "CreateDamageTracking Failed ({0}): {1}", end.Positioned, ex)); throw; } Trace.Assert(stagingRange.Positioned && stagingRange.Start.Positioned && stagingRange.End.Positioned && sc1.Positioned && sc2.Positioned, String.Format(CultureInfo.InvariantCulture, "Staging document corrupt after CreateDamageTracking. stagingRange:({0}),stagingRange.Start:({1}),stagingRange.End:({2}),sc1:({3}),sc2:({4})", stagingRange.Positioned, stagingRange.Start.Positioned, stagingRange.End.Positioned, sc1.Positioned, sc2.Positioned)); using (damageTracker) { // CT: Because we don't set gravity, these pointers can end up in indeterminant positions. // For example, when inserting HTML over a selection inside of a block, the start // pointer can end up on the right side of the end pointer. Pushing gravity onto // the pointers before we call this should provide consistent markup pointer behavior. try { start.PushGravity(_POINTER_GRAVITY.POINTER_GRAVITY_Left); end.PushGravity(_POINTER_GRAVITY.POINTER_GRAVITY_Right); Trace.Assert(stagingRange.Positioned && stagingRange.Start.Positioned && stagingRange.End.Positioned && sc1.Positioned && sc2.Positioned, String.Format(CultureInfo.InvariantCulture, "Staging document corrupt after applying gravity. stagingRange:({0}),stagingRange.Start:({1}),stagingRange.End:({2}),sc1:({3}),sc2:({4})", stagingRange.Positioned, stagingRange.Start.Positioned, stagingRange.End.Positioned, sc1.Positioned, sc2.Positioned)); try { MarkupServices.Move(stagingRange.Start, stagingRange.End, end); } catch (COMException ex) { Trace.WriteLine( String.Format(CultureInfo.InvariantCulture, "MarkupServices.Move Failed ({0},{1},{2}): {3}", stagingRange.Start.Positioned, stagingRange.End.Positioned, end.Positioned, ex)); throw; } } finally { end.PopGravity(); start.PopGravity(); } if (allowNewLineInsert && TidyWhitespace) { try { EnsureNewLineAtDocEnd(mpStart, mpEnd); } catch (Exception ex) { Trace.WriteLine("Failed to insert new line at end of document: " + ex); } } } } // note that we have completed our edit undoUnit.Commit(); start.PopCling(); end.PopCling(); } }