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> /// Select all of the text in the region. /// </summary> protected void SelectAll() { MarkupRange selectRange = ElementRange.Clone(); selectRange.MoveToElement(HTMLElement, false); selectRange.ToTextRange().select(); }
/// <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); }
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(); } } }
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); }
/// <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); }
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); }
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); }
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); }
private bool ValidateTableSelection(IHTMLTable table, MarkupRange selectionMarkupRange, out bool tableFullySelected) { // assume table is not fully selected tableFullySelected = false; // first check to see that this is a "Writer" editable table if (!TableHelper.TableElementContainsWriterEditingMark(table as IHTMLElement)) { return(false); } // get elemental objects we need to analyze the table IHTMLElement tableElement = table as IHTMLElement; MarkupRange tableMarkupRange = selectionMarkupRange.Clone(); tableMarkupRange.MoveToElement(table as IHTMLElement, true); // analyze selection bool selectionAtTableStart = tableMarkupRange.Start.IsEqualTo(selectionMarkupRange.Start); bool selectionAtTableEnd = tableMarkupRange.End.IsEqualTo(selectionMarkupRange.End); // is the table fully selected? if (selectionAtTableStart && selectionAtTableEnd) { tableFullySelected = true; return(true); } else { MarkupRange selectionMarkupRange2 = selectionMarkupRange.Clone(); // is the selection bounded by the table IHTMLElement beginParentTable = selectionMarkupRange2.Start.SeekElementLeft(ElementFilters.CreateEqualFilter(tableElement)); IHTMLElement endParentTable = selectionMarkupRange2.End.SeekElementRight(ElementFilters.CreateEqualFilter(tableElement)); return(beginParentTable != null && endParentTable != null); } }
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); }
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); }