protected override bool DoInsertData(DataAction action, MarkupPointer begin, MarkupPointer end) { // get a reference to the underlying data object IDataObject dataObject = DataMeister.IDataObject; string dataObjectInstanceId = dataObject.GetData(SmartContentDataObject.INSTANCE_ID_DATAFORMAT) as string; if (EditorContext.EditorId.Equals(dataObjectInstanceId)) { // get the internal items out of the data object string smartContentElementId = (string)dataObject.GetData(SmartContentDataObject.INTERNAL_SMART_CONTENT_DATAFORMAT); IHTMLElement element = (EditorContext.HtmlDocument as IHTMLDocument3).getElementById(smartContentElementId); Debug.Assert(element != null, "Invalid smart content item id detected: " + smartContentElementId); if (element != null) { MarkupRange elementRange = EditorContext.MarkupServices.CreateMarkupRange(element, true); MarkupPointer insertionPoint = begin; MarkupPointerMoveHelper.PerformImageBreakout(insertionPoint); insertionPoint.PushCling(false); insertionPoint.PushGravity(_POINTER_GRAVITY.POINTER_GRAVITY_Left); //verify the insertion point is inside of the same content editable parent (bug 290729) if (!IsValidInsertionPoint(element, insertionPoint)) { return(false); } try { if (InlineEditField.IsEditField(insertionPoint.CurrentScope)) { // If we are in an edit field, since we strip the content wdown to plain text we have to use // InsertHtml. However, this means we need to move the content via a string. This sucks because // we break any markup ranges in that area. This is why ignore once will not work in edit fields. EditorContext.MarkupServices.Remove(begin, end); string html = elementRange.HtmlText; EditorContext.MarkupServices.Remove(elementRange.Start, elementRange.End); EditorContext.InsertHtml(insertionPoint, insertionPoint, html, null); } else { EditorContext.MarkupServices.Remove(begin, end); EditorContext.MarkupServices.Move(elementRange.Start, elementRange.End, insertionPoint); } return(true); } finally { insertionPoint.PopCling(); insertionPoint.PopGravity(); } } } return(false); }
public bool IsAdjacentToWordEnd(MarkupPointer p) { lock (_p) { _p.MoveToPointer(p); _p.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_NEXTCHAR); _p.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_PREVWORDEND); return(_p.IsEqualTo(p)); } }
public bool IsAdjacentToWordStart(MarkupPointer p) { lock (_p) { _p.MoveToPointer(p); _p.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_PREVCHAR); _p.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_NEXTWORDBEGIN); return(_p.IsEqualTo(p)); } }
public IDisposable CreateDamageTracker(MarkupPointer start, MarkupPointer end, bool includeAdjacentWords) { if (DamageTrackingEnabled) { return(new DamageTracker(this, start, end, includeAdjacentWords)); } else { return(null); } }
private string GetHtmlText(out MarkupPointer blockBoundary) { MarkupRange blockRange = _blogPostHtmlEditorControl.SelectedMarkupRange.Clone(); MarkupRange textRange = blockRange.Clone(); IHTMLElement ele = blockRange.ParentElement(ElementFilters.IsBlockOrTableCellOrBodyElement); if (ele == null) { blockBoundary = null; return(String.Empty); } blockRange.MoveToElement(ele, false); blockBoundary = blockRange.Start; // Fix Bug 616152 - We want the start and end pointer to match so // we can look back from the start of the insertion point (not the end, // which would include the selection that is going to be overwritten) textRange.Collapse(true); // Fix bug WinLive 59172: Specific characters of mixed characters are broken in mail body after press the 'Enter' key // Caused by using MOVEUNIT_PREVCHAR to navigate into Unicode surrogate (32-bit) characters. We work around this by moving // only at word or block boundaries. string html = null; do { int startPos = textRange.Start.MarkupPosition; textRange.Start.MoveUnitBounded(_MOVEUNIT_ACTION.MOVEUNIT_PREVWORDBEGIN, blockBoundary); if (textRange.Start.MarkupPosition == startPos) { // PREVWORDBEGIN didn't actually move us, due to no word being available. // To avoid an infinite loop, just move the text range to include the whole // block and move on. textRange.Start.MoveToPointer(blockRange.Start); break; } if (textRange.Positioned && textRange.Start.IsLeftOfOrEqualTo(textRange.End)) { html = MarkupHelpers.GetRangeTextFast(textRange); } html = html ?? string.Empty; } while (html.Length < MinLookBack && textRange.Start.IsRightOf(blockRange.Start)); if (html == null && textRange.Positioned && textRange.Start.IsLeftOfOrEqualTo(textRange.End)) { html = MarkupHelpers.GetRangeTextFast(textRange); } return(html ?? string.Empty); }
//remove any covered segments from the tracker and clear their highlights public void ClearRange(MarkupPointer start, MarkupPointer end) { IHighlightSegmentRaw[] segments = _tracker.GetSegments(start.PointerRaw, end.PointerRaw); if (segments != null) { for (int i = 0; i < segments.Length; i++) { _highlightRenderingServices.RemoveSegment(segments[i]); } } }
protected override bool DoInsertData(DataAction action, MarkupPointer begin, MarkupPointer end) { // get the live clipboard data LiveClipboardData lcData = DataMeister.LiveClipboardData; if (lcData == null) { Trace.Fail("Unexpected failure to get LC data!"); return(false); } // lookup the content-source ContentSourceInfo contentSource = LiveClipboardManager.FindContentSourceForLiveClipboard(lcData.Formats); if (contentSource == null) { Trace.Fail("Unexpected failure to find content soure!"); return(false); } using (new WaitCursor()) { try { // HACK: drive the selection textRange to the caret so we can call generic // content-source routines that work off the current selection // Note that we do the same thing below for Images so we can use the common // InsertImages method -- we may want to bake this into core marshalling // or add MarkupRange parameters to the image and content-source routines EditorContext.MarkupServices.CreateMarkupRange(begin, end).ToTextRange().select(); if (contentSource.Instance is SmartContentSource) { return(InsertSmartContentFromLiveClipboard(contentSource, lcData.Document)); } else if (contentSource.Instance is ContentSource) { return(InsertSimpleContentFromLiveClipboard(contentSource, lcData.Document)); } else { Debug.Fail("Unexpected content source type: " + contentSource.GetType()); return(false); } } catch (Exception ex) { ContentSourceManager.DisplayContentRetreivalError(EditorContext.FrameWindow, ex, contentSource); 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 MovePointerRightUntilRegionBreak(MarkupPointer p, IHTMLElementFilter regionBreakFilter, MarkupPointer rightBoundary) { MarkupContext moveContext = new MarkupContext(); while (p.IsLeftOf(rightBoundary)) { p.Right(true, moveContext); if (moveContext.Element != null && regionBreakFilter(moveContext.Element)) { p.Left(true); return; } } }
/// <summary> /// Prepare the HTML selection to deal with keyboard navigation events. /// </summary> /// <param name="direction"></param> /// <param name="selectBlock"></param> private void PrepareForKeyboardNavigation(MarkupDirection direction, bool selectBlock) { if (direction == MarkupDirection.Left && selectBlock) { //HACK: make shift+Left keep the div selected by putting the selection at the //right-side of the div before the key event is handled. MarkupPointer caretPointer = EditorContext.MarkupServices.CreateMarkupPointer(HTMLElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); EditorContext.MarkupServices.CreateMarkupRange(caretPointer, caretPointer).ToTextRange().select(); } else { ElementRange.ToTextRange().select(); } }
/// <summary> /// Instruct the handler to insert data into the presentation editor /// </summary> protected override bool DoInsertData(DataAction action, MarkupPointer begin, MarkupPointer end) { string imagePath = SaveImageDataToTempFile(DataMeister.ImageData); if (imagePath != null) { //hack: drive the selection textRange to the caret (before calling InsertImages) EditorContext.MarkupServices.CreateMarkupRange(begin, end).ToTextRange().select(); _blogEditor.InsertImages(new string[] { imagePath }, ImageInsertEntryPoint.DragDrop); return(true); } return(false); }
/// <summary> /// Grabs an HTML img copied in the clipboard and pastes it into the document. /// </summary> protected override bool DoInsertData(DataAction action, MarkupPointer begin, MarkupPointer end) { using (new WaitCursor()) { try { HTMLData htmlData = DataMeister.HTMLData; string baseUrl = UrlHelper.GetBaseUrl(htmlData.SourceURL); string html = htmlData.HTMLSelection; if (HtmlHandler.IsPasteFromSharedCanvas(DataMeister)) { if (action == DataAction.Move) { // if we are dragging and dropping the image, we need to grow to find the anchor for an image html = GrowToAnchorParent(htmlData); } else { // if we are copying and pasting an image from writer, we need to change temp path references the orginal file path if (htmlData.OnlyImageElement != null) { // WinLive 96840 - Copying and pasting images within shared canvas should persist source // decorator settings. "wlCopySrcUrl" is inserted while copy/pasting within canvas. // Insert wlCopySrcUrl attribute html = ImageCopyFixupHelper.FixupSourceUrlForCopy(html); } html = EditorContext.FixImageReferences(html, htmlData.SourceURL); } } else { html = EditorContext.FixImageReferences(html, htmlData.SourceURL); html = EditorContext.HtmlGenerationService.CleanupHtml(html, baseUrl, HtmlCleanupRule.Normal); } html = EditorContext.HtmlGenerationService.GenerateHtmlFromHtmlFragment(html, baseUrl); EditorContext.InsertHtml(begin, end, html, DataMeister.HTMLData.SourceURL); 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); } } }
public void MoveToWordStart(MarkupPointer p) { lock (_p) { _p.MoveToPointer(p); _p2.MoveToPointer(p); _p.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_PREVWORDEND); _p2.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_PREVWORDBEGIN); if (_p2.IsRightOfOrEqualTo(_p)) { p.MoveToPointer(_p2); } //else, the pointer is already at the start of the current word } }
private void DeleteInsertionTargetBlockIfEmpty(MarkupPointer insertionPoint) { //locate the parent block element (stop at post body element) IHTMLElement parent = insertionPoint.GetParentElement( ElementFilters.CreateCompoundElementFilter(ElementFilters.CreateElementEqualsFilter(HTMLElement), ElementFilters.BLOCK_ELEMENTS)); if (parent != null && parent.sourceIndex != HTMLElement.sourceIndex && //never remove the post body block EditorContext.MarkupServices.CreateMarkupRange(parent, false).IsEmptyOfContent()) { //delete the empty parent block element (parent as IHTMLDOMNode).removeNode(true); } }
/// <summary> /// Wraps the range from startPointer to endPointer with the given element (as long as the range is non-empty) /// and then moves the pointers past the inserted element. /// </summary> /// <param name="element">The element to wrap the range in.</param> /// <param name="markupServices">The MarkupServices for the start and end pointers.</param> /// <param name="startPointer">Pointer to place the beginning of the element.</param> /// <param name="endPointer">Pointer to place the end of the element.</param> private void InsertElement(IHTMLElement element, MshtmlMarkupServices markupServices, MarkupPointer startPointer, MarkupPointer endPointer) { Debug.Assert(startPointer.IsLeftOfOrEqualTo(endPointer), "Expected start to be left of or equal to end!"); Debug.Assert(HTMLElementHelper.ElementsAreEqual(startPointer.CurrentScope, endPointer.CurrentScope), "Expected start and end to be in the same scope, otherwise resulting HTML will be invalid!"); if (startPointer.IsLeftOf(endPointer)) { markupServices.InsertElement(element, startPointer, endPointer); } endPointer.Right(true); startPointer.MoveToPointer(endPointer); }
/// <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)); }
internal MarkupRange CreateDamageTrackingRange(MarkupPointer start, MarkupPointer end, bool includeAdjecentWords) { MarkupRange range = _mshtmlEditor.MshtmlControl.MarkupServices.CreateMarkupRange(); range.Start.MoveToPointer(start); range.Start.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Left; range.End.MoveToPointer(end); range.End.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Right; _wordHelper.MoveToWordStart(range.Start); _wordHelper.MoveToWordEnd(range.End); if (includeAdjecentWords) { ExpandDamageToAdjacentWords(range); } return(range); }
/// <summary> /// Returns the markup pointer that is most deeply placed within the DOM. /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <returns></returns> private MarkupPointer GetDeeperPoint(MarkupPointer p1, MarkupPointer p2) { IHTMLElement startElement = p1.CurrentScope; IHTMLElement endElement = p2.CurrentScope; int startSourceIndex = startElement != null ? startElement.sourceIndex : -1; int endSourceIndex = startElement != null ? endElement.sourceIndex : -1; if (startSourceIndex > endSourceIndex || (startSourceIndex == endSourceIndex && p1.IsRightOfOrEqualTo(p2))) { return(p1); } else { return(p2); } }
protected bool DoInsertDataCore(List <string> files, DataAction action, MarkupPointer begin, MarkupPointer end) { IHtmlEditorHost blogEditor = _blogEditor; ImageInsertEntryPoint imageInsertEntryPoint = ImageInsertEntryPoint; EditorContext.Invoke(delegate { //hack: drive the selection textRange to the caret (before calling InsertImages) EditorContext.MarkupServices.CreateMarkupRange(begin, end).ToTextRange().select(); string[] fileArray = files.ToArray(); blogEditor.InsertImages(fileArray, ImageInsertEntryPoint.DragDrop); }); return(true); }
/// <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> /// Returns true if there is text to the right of the current position. /// </summary> /// <returns></returns> protected bool hasTextRight(MarkupPointer pointer) { MarkupPointer start = pointer; MarkupPointer end = ElementRange.End; IHTMLTxtRange textRange = EditorContext.MarkupServices.CreateTextRange(start, end); string text = textRange.text; if (text == null || text.Trim().Equals(String.Empty)) { return(false); } else { return(true); } }
private IHTMLElement CreateNodeForCentering() { // Create markup services using the element's document that we are analyzing MshtmlMarkupServices MarkupServices = new MshtmlMarkupServices(_element.document as IMarkupServicesRaw); MarkupPointer end = MarkupServices.CreateMarkupPointer(); MarkupPointer start = MarkupServices.CreateMarkupPointer(); // Find the element that we will want to wrap. IHTMLElement elementToEncapsulate = _element; // If the elements parent is an A, we will also want to // wrap the A and not just the image inside if (_element.parentElement.tagName == "A") { elementToEncapsulate = _element.parentElement; } // Move the starting pointer to before the begining of the element we want to wrap start.MoveAdjacentToElement(elementToEncapsulate, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin); // Find this elements parent IHTMLElement3 currentBlockScope = start.CurrentBlockScope() as IHTMLElement3; // If its parent is also the div that is around the post // we need to actually create a new div and just put it around the element // If it is splittable block, split it // e.g "<DIV>Blah<IMG/>Blah</DIV>" => "<DIV>Blah</DIV><DIV><IMG/></DIV><DIV>Blah</DIV>" if (!IsBodyElement(currentBlockScope)) { // We are in a block that can be split so split it at the begining and end MarkupHelpers.SplitBlockForInsertionOrBreakout(MarkupServices, null, start); end.MoveAdjacentToElement(elementToEncapsulate, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); MarkupHelpers.SplitBlockForInsertionOrBreakout(MarkupServices, null, end); // Position start back to the beginning of our element start.MoveAdjacentToElement(elementToEncapsulate, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin); } // Now we can wrap it in an P tag (centering node) end.MoveAdjacentToElement(elementToEncapsulate, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); IHTMLElement centeringElement = MarkupServices.CreateElement(_ELEMENT_TAG_ID.TAGID_P, string.Empty); MarkupServices.InsertElement(centeringElement, start, end); return(centeringElement); }
protected override bool DoInsertData(DataAction action, MarkupPointer begin, MarkupPointer end) { // get the list of files from the data meister FileItem[] files = DataMeister.FileData.Files; List <string> filePaths = new List <string>(DataMeister.FileData.Files.Length); // create an array of file entities to insert for (int i = 0; i < files.Length; i++) { if (PathHelper.IsPathImage(files[i].ContentsPath)) { filePaths.Add(files[i].ContentsPath); } } return(DoInsertDataCore(filePaths, action, begin, end)); }
public void MoveToWordEnd(MarkupPointer p) { lock (_p) { _p.MoveToPointer(p); _p2.MoveToPointer(p); _p.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_NEXTWORDBEGIN); _p2.MoveUnit(_MOVEUNIT_ACTION.MOVEUNIT_NEXTWORDEND); // If CurrentScope is null, this means we have walked off the end of the // document, in that case we don't want to move the pointer, at is already // at the end of word. if (_p2.IsLeftOfOrEqualTo(_p) && _p.CurrentScope != null) { p.MoveToPointer(_p2); } //else, the pointer is already at the end of the current word } }
private void HandleEnterKey(HtmlEventArgs e) { //pressing the enter key on an empty line is used as a gesture for exiting the blockquote //If this situation is encountered, move the current empty block element outside of the blockquote MarkupRange selection = EditorContext.Selection.SelectedMarkupRange; if (selection.IsEmpty()) { MarkupPointer selectionPoint = EditorContext.MarkupServices.CreateMarkupPointer(selection.Start); selectionPoint.Cling = true; IHTMLElement currBlock = selection.Start.CurrentBlockScope(); MarkupRange currBlockRange = EditorContext.MarkupServices.CreateMarkupRange(currBlock, false); if (currBlockRange.IsEmptyOfContent()) { currBlockRange.MoveToElement(currBlock, true); // Make sure there is no content between the end of this block range and the end of the blockquote. MarkupPointer afterEndCurrBlock = EditorContext.MarkupServices.CreateMarkupPointer(currBlock, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); MarkupPointer beforeEndBlockQuote = EditorContext.MarkupServices.CreateMarkupPointer(HTMLElement, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeEnd); MarkupRange restOfBlockQuote = EditorContext.MarkupServices.CreateMarkupRange(afterEndCurrBlock, beforeEndBlockQuote); if (!restOfBlockQuote.IsEmpty() || !restOfBlockQuote.IsEmptyOfContent()) { return; } //create a pointer for the new location that the block element will be moved to. MarkupPointer insertionPoint = EditorContext.MarkupServices.CreateMarkupPointer(HTMLElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); //move the current empty block to the DOM location after the blockquote EditorContext.MarkupServices.Move(currBlockRange.Start, currBlockRange.End, insertionPoint); currBlockRange.MoveToElement(currBlock, false); //adjust the selection to the new location of the block element. currBlockRange.Start.MoveToPointer(selectionPoint); currBlockRange.End.MoveToPointer(selectionPoint); currBlockRange.ToTextRange().select(); //cancel the key down event so that the editor doesn't try to handle it e.Cancel(); } } }
/// <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); }
protected override bool DoInsertData(DataAction action, MarkupPointer begin, MarkupPointer end) { //hack: drive the selection textRange to the caret (before calling InsertImages) EditorContext.MarkupServices.CreateMarkupRange(begin, end).ToTextRange().select(); List <string> files = new List <string>(); DirectoryLister lister = new DirectoryLister(DataMeister.FileData.Files[0].ContentsPath, false, true); foreach (string file in lister.GetFiles()) { if (PathHelper.IsPathImage(file)) { files.Add(Path.Combine(lister.RootPath, file)); } } return(DoInsertDataCore(files, action, begin, end)); }
/// <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); }
//iterates through a word range checking for spelling errors //return: whether the word range is finished (true) or not private bool ProcessWordRange(MshtmlWordRange wordRange) { if (wordRange.CurrentWordRange.Positioned) { //track where we will need to clear; MarkupPointer start = _markupServices.CreateMarkupPointer(); start.MoveToPointer(wordRange.CurrentWordRange.End); ArrayList highlightwords = new ArrayList(NUMBER_OF_WORDS_TO_CHECK); int i = 0; //to do....the word range is losing its place when it stays in the queue while (wordRange.HasNext() && i < NUMBER_OF_WORDS_TO_CHECK) { // advance to the next word wordRange.Next(); // check the spelling int offset, length; if (ProcessWord(wordRange, out offset, out length)) { MarkupRange highlightRange = wordRange.CurrentWordRange.Clone(); MarkupHelpers.AdjustMarkupRange(ref stagingTextRange, highlightRange, offset, length); //note: cannot just push the current word range here, as it moves before we get to the highlighting step highlightwords.Add(highlightRange); } i++; } MarkupPointer end = wordRange.CurrentWordRange.End; //got our words, clear the checked range and then add the misspellings ClearRange(start, end); foreach (MarkupRange word in highlightwords) { HighlightWordRange(word); } return(!wordRange.HasNext()); } else { return(true); } }
/// <summary> /// <font><span>aaa[splitPoint]bbb</span></font> --> <font><span>aaa</span></font><font>[splitPoint]<span>bbb</span></font> /// </summary> private void SplitInlineTags(MarkupPointer splitPoint) { Debug.Assert(splitPoint.Positioned); IHTMLElement currentElement = splitPoint.GetParentElement(ElementFilters.CreateElementPassFilter()); while (currentElement != null) { if (!ElementFilters.IsInlineElement(currentElement)) { return; } IHTMLElement parentElement = currentElement.parentElement; MarkupRange currentElementRange = _markupServices.CreateMarkupRange(currentElement, false); MarkupRange leftRange = _markupServices.CreateMarkupRange(); IHTMLElement leftElement = _markupServices.CreateElement(_markupServices.GetElementTagId(currentElement), null); HTMLElementHelper.CopyAttributes(currentElement, leftElement); leftRange.MoveToPointers(currentElementRange.Start, splitPoint); _markupServices.InsertElement(leftElement, leftRange.Start, leftRange.End); splitPoint.MoveAdjacentToElement(leftElement, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); MarkupRange rightRange = _markupServices.CreateMarkupRange(); IHTMLElement rightElement = _markupServices.CreateElement(_markupServices.GetElementTagId(currentElement), null); HTMLElementHelper.CopyAttributes(currentElement, rightElement); rightRange.MoveToPointers(splitPoint, currentElementRange.End); #if DEBUG // Verify that the right range does not overlap the left *element* MarkupRange leftElementRange = _markupServices.CreateMarkupRange(leftElement, true); Debug.Assert(leftElementRange.End.IsLeftOfOrEqualTo(rightRange.Start), "Your right range overlaps the left element that you just created!"); #endif _markupServices.InsertElement(rightElement, rightRange.Start, rightRange.End); splitPoint.MoveAdjacentToElement(rightElement, _ELEMENT_ADJACENCY.ELEM_ADJ_BeforeBegin); _markupServices.RemoveElement(currentElement); currentElement = parentElement; } }
/// <summary> /// Create a TextRange that spans a set of pointers. /// </summary> /// <param name="start"></param> /// <param name="end"></param> /// <returns></returns> public IHTMLTxtRange CreateTextRange(MarkupPointer start, MarkupPointer end) { Debug.Assert(start.Positioned && end.Positioned, "pointers are not positioned"); IHTMLTxtRange range = start.Container.CreateTextRange(start, end); return range; }
/// <summary> /// Positions pointers at the edges of an existing range. /// </summary> /// <param name="start">the pointer positioned at the start of the range</param> /// <param name="end">the pointer position at the end of the range</param> /// <param name="range">the text range to move</param> public void MoveRangeToPointers(MarkupPointer start, MarkupPointer end, IHTMLTxtRange range) { MarkupServices.MoveRangeToPointers(start.PointerRaw, end.PointerRaw, range); }
/// <summary> /// Creates an instance of the IMarkupPointer object with an initial position /// at the same location as another pointer. /// </summary> /// <param name="initialPosition"></param> /// <returns></returns> public MarkupPointer CreateMarkupPointer(MarkupPointer initialPosition) { MarkupPointer pointer = CreateMarkupPointer(); pointer.MoveToPointer(initialPosition); return pointer; }
/// <summary> /// Positions pointers at the edges of an existing range. /// </summary> /// <param name="range">the text range to move to</param> /// <param name="start">the pointer to position at the start of the range</param> /// <param name="end">the pointer to position at the end of the range</param> public void MovePointersToRange(IHTMLTxtRange range, MarkupPointer start, MarkupPointer end) { MarkupServices.MovePointersToRange(range, start.PointerRaw, end.PointerRaw); }
/// <summary> /// Create a MarkupRange from a set of MarkupPointers. /// </summary> /// <param name="start"></param> /// <param name="end"></param> /// <returns></returns> public MarkupRange CreateMarkupRange(MarkupPointer start, MarkupPointer end) { MarkupRange markupRange = new MarkupRange(start, end, this); return markupRange; }