private bool IsValidInsertionPoint(IHTMLElement e, MarkupPointer p) { if (InlineEditField.IsEditField(p.CurrentScope)) { return(true); } IHTMLElement contentEditableParent = null; IHTMLElement parent = e; while (parent != null) { if ((parent as IHTMLElement3).isContentEditable) { contentEditableParent = parent; } else if (contentEditableParent != null) { break; //we hit the top-most editable parent. } parent = parent.parentElement; } if (contentEditableParent != null) { MarkupRange range = EditorContext.MarkupServices.CreateMarkupRange(contentEditableParent, false); return(range.InRange(p)); } else { return(false); } }
/// <summary> /// Wraps a MarkupRange in an element (or multiple elements if necessary to produce valid HTML). /// </summary> /// <param name="elementFactory">Creates elements to wrap the markupRange in as needed.</param> /// <param name="markupServices">The MarkupServices for the markupRange.</param> /// <param name="markupRange">The range to wrap.</param> protected void WrapInElement(ElementFactory elementFactory, MshtmlMarkupServices markupServices, MarkupRange markupRange) { Debug.Assert(markupRange.GetElements(ElementFilters.BLOCK_ELEMENTS, false).Length == 0, "Did not expect MarkupRange to contain block elements"); MarkupPointer startPointer = markupRange.Start.Clone(); MarkupPointer endPointer = markupRange.Start.Clone(); MarkupContext context; while (endPointer.IsLeftOf(markupRange.End)) { context = endPointer.Right(false); if (context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope || context.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_ExitScope) { if (!markupRange.InRange(context.Element)) { // EnterScope example: <span>[markupRange.Start]Hello [endPointer]<i>Hello[markupRange.End]</i></span> // ExitScope example: <span>[markupRange.Start]Hello [endPointer]</span><span>Hello[markupRange.End]</span> InsertElement(elementFactory(), markupServices, startPointer, endPointer); continue; } } endPointer.Right(true); } InsertElement(elementFactory(), markupServices, startPointer, endPointer); }
/// <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); } } }
private void SplitBlockForApplyingBlockStyles(MarkupPointer splitPoint, MarkupRange maximumBounds) { //find the split stop parent IHTMLElement splitStop = splitPoint.GetParentElement(new IHTMLElementFilter(IsSplitStopElement)); if (splitStop != null) { MarkupPointer stopLocation = _markupServices.CreateMarkupPointer(splitStop, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterBegin); if (maximumBounds.InRange(stopLocation)) { stopLocation.MoveAdjacentToElement(splitStop, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd); if (maximumBounds.InRange(stopLocation)) { maximumBounds = maximumBounds.Clone(); maximumBounds.MoveToElement(splitStop, false); } } } MarkupHelpers.SplitBlockForInsertionOrBreakout(_markupServices, maximumBounds, splitPoint); }
/// <summary> /// Returns true if the parent element was removed and false otherwise. /// </summary> private bool RemoveEmptyParentBlock(MarkupRange range, IHTMLElement parentBlock, MarkupRange maximumBounds) { if (parentBlock != null) { range.MoveToElement(parentBlock, false); if (maximumBounds.InRange(range) && range.IsEmptyOfContent()) { if (!IsSplitStopElement(parentBlock)) { //delete the parent node (only if it doesn't fall outside the maxrange (bug 465995)) range.MoveToElement(parentBlock, true); //expand the range around deletion area to test for maxBounds exceeded if (maximumBounds.InRange(range)) { (parentBlock as IHTMLDOMNode).removeNode(true); return(true); } } } } return(false); }
/// <summary> /// Notify the data format handler that data was dropped and should be inserted into /// the document at whatever insert location the handler has internally tracked. /// </summary> /// <param name="action"></param> public override bool DataDropped(DataAction action) { if (currentCaretLocation == null) { return(false); } // create two markup pointers that map to the location of the caret MarkupPointer begin = EditorContext.MarkupServices.CreateMarkupPointer(); MarkupPointer end = EditorContext.MarkupServices.CreateMarkupPointer(); EditorContext.MarkupServices.MoveMarkupPointerToCaret(currentCaretLocation, begin); MarkupPointerMoveHelper.PerformImageBreakout(begin); //optimize the drop location to keep it from being in an unexpected location (fixes bug 395224) if (EditorContext.ShouldMoveDropLocationRight(begin)) { begin.Right(true); } //synchronize the end pointer with the being pointer end.MoveToPointer(begin); MarkupRange selectedRange = EditorContext.SelectedMarkupRange; // WinLive 91888 Photomail image drag drop loses images //if (!selectedRange.IsEmpty() && selectedRange.InRange(end)) if (!selectedRange.IsEmpty() && selectedRange.InRange(end, false)) { //the drop location is over the drag source location, so don't so anything. return(false); } // Forces a SelectionChanged event so that the correct behaviors around the drop location are activated. // For example, one side effect of this call is that the OnEditableRegionFocusChanged event is fired, which // sets whether the current drop location in the canvas supports images, html and/or text. MarkupRange dropRange = EditorContext.MarkupServices.CreateMarkupRange(begin, end); dropRange.ToTextRange().select(); try { // insert the data at the current insertion point return(InsertData(action, begin, end)); } catch (Exception e) { Trace.Fail(e.Message, e.StackTrace); return(false); } }
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); }
internal bool Restore(MarkupRange selection, MarkupRange bounds) { if (initialMarkup == null) { return(false); } NormalizeBounds(ref bounds); /* * if (initialMarkup != bounds.HtmlText) * { * Trace.Fail("Unexpected markup"); * Trace.WriteLine(initialMarkup); * Trace.WriteLine(bounds.HtmlText); * return false; * } */ selection.Start.MoveToPointer(bounds.Start); if (movesRight == int.MaxValue) { selection.Start.MoveToPointer(bounds.End); } else { for (int i = 0; i < movesRight; i++) { selection.Start.Right(true); } } for (int i = 0; i < charsLeft; i++) { selection.Start.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_PREVCHAR); } selection.Collapse(true); selection.ToTextRange().select(); Debug.Assert(bounds.InRange(selection, true), "Selection was out of bounds"); return(true); }
/// <summary> /// Returns true if a word range is in this list that contains this markup pointer. /// </summary> public bool Contains(MarkupPointer p) { if (words.Count == 0) { return(false); } // Just being defensive if (!p.Positioned) { return(false); } int idx = BinarySearch(words.Keys, p.PointerRaw, new MarkupPointerComparer()); if (idx >= 0) { return(true); } idx = ~idx; // really this could be "if (idx == words.Count)"--it's to handle the case // where p is larger than the values in the list while (idx >= words.Count) { idx--; } for (; idx >= 0; idx--) { MarkupRange wordRange = words.Values[idx]; if (wordRange.InRange(p)) { return(true); } if (wordRange.End.IsLeftOf(p)) { break; } } return(false); }
private bool IsValidEmoticonInsertionPoint() { MarkupRange selection = _currentSelection.Clone(); // Check to make sure the target is not in an edit field if (InlineEditField.IsWithinEditField(selection.ParentElement())) { return(false); } // Check to make sure the target is in the body of the post selection.MoveToElement(_postBodyElement, false); if (!selection.InRange(_currentSelection)) { return(false); } return(true); }
public void ClearRange(MarkupRange clear) { if (words.Count == 0) { return; } // Just being defensive here if (!clear.Positioned) { return; } // Debug.WriteLine(string.Format("ClearRange:\r\n{0}\r\n{1}", clear.Start.PositionTextDetail, clear.End.PositionTextDetail)); /* * Start from the first range in the list where the start is left of * the Clear range's end. Take a look at each range until you get to * one where the range's end is left of the Clear range's start. */ int idx = BinarySearch(words.Keys, clear.Start.PointerRaw, new MarkupPointerComparer()); if (idx < 0) { idx = ~idx; idx--; idx = Math.Max(0, idx); } for (; idx < words.Count; idx++) { MarkupRange range = words.Values[idx]; // Debug.WriteLine("Testing range: " + range.Text); if (!range.Positioned) { // Debug.WriteLine("ClearRange: Removing unpositioned word"); words.RemoveAt(idx--); } else if (clear.End.IsLeftOfOrEqualTo(range.Start)) { // Debug.WriteLine("We've gone far enough--all done"); return; } else if (clear.InRange(range)) { // Debug.WriteLine("ClearRange: Removing contained range"); words.RemoveAt(idx--); } else if (range.InRange(clear)) { // Debug.WriteLine("ClearRange: Splitting range"); MarkupRange trailingRange = range.Clone(); trailingRange.Start.MoveToPointer(clear.End); range.End.MoveToPointer(clear.Start); if (range.IsEmpty()) { words.RemoveAt(idx--); } if (!trailingRange.IsEmpty()) { Add(trailingRange); } } else if (range.InRange(clear.End, false)) { // Debug.WriteLine("ClearRange: Partial overlap, trimming from start of range"); words.RemoveAt(idx--); range.Start.MoveToPointer(clear.End); if (!range.IsEmpty()) { Add(range); } } else if (range.InRange(clear.Start, false)) { // Debug.WriteLine("ClearRange: Partial overlap, trimming from end of range"); range.End.MoveToPointer(clear.End); if (range.IsEmpty()) { words.RemoveAt(idx--); } } } // Debug.WriteLine("ClearRange: Remaining words in ignore list: " + words.Count); }