/// <summary> /// Inspects the range if a new font tag need to be added to apply formatting for the range. /// Call this only for ranges that are inside a header element /// </summary> private void WrapRangeInFontIfNecessary(MarkupRange currentRange, bool turnBold) { // Check if there is an existing font/span tag that completely wraps this range, // we can just use that instead of inserting a new one MarkupContext workingContext = new MarkupContext(); bool wrapFont = true; MarkupPointer start = currentRange.Start.Clone(); start.Gravity = _POINTER_GRAVITY.POINTER_GRAVITY_Left; start.Right(false, workingContext); // Look to the right to see what we have there if (workingContext.Element != null && workingContext.Context == _MARKUP_CONTEXT_TYPE.CONTEXT_TYPE_EnterScope && IsFontableElement(workingContext.Element)) { start.MoveAdjacentToElement(workingContext.Element, _ELEMENT_ADJACENCY.ELEM_ADJ_AfterEnd); if (currentRange.End.IsEqualTo(start)) { // There is an existing <FONT>/<SPAN> enclosing the range, no need to wrap again wrapFont = false; // set its font-weight workingContext.Element.style.fontWeight = turnBold ? "bold" : "normal"; } } if (wrapFont) { string weightAttribute = String.Format(CultureInfo.InvariantCulture, "style=\"font-weight: {0}\"", turnBold ? "bold" : "normal"); HtmlStyleHelper.WrapRangeInElement(markupServices, currentRange, _ELEMENT_TAG_ID.TAGID_FONT, weightAttribute); } }
public static void ClearBackgroundColor(MshtmlMarkupServices markupServices, MarkupRange selection) { HtmlStyleHelper htmlStyleHelper = new HtmlStyleHelper(markupServices); htmlStyleHelper.SplitInlineTags(selection.Start); htmlStyleHelper.SplitInlineTags(selection.End); IHTMLElement[] elements = selection.GetElements(ElementFilters.CreateTagIdFilter("font"), false); foreach (IHTMLElement element in elements) { element.style.backgroundColor = ""; } // We may now be left with empty font tags, e.g. <font>blah</font>. // After switching between editors this becomes <font size="+0">blah</font>, which // causes blah to be rendered differently. // To avoid that we need to remove any empty-attribute font tags. selection.RemoveElementsByTagId(_ELEMENT_TAG_ID.TAGID_FONT, 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)); }
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 void SplitInlineTags(MshtmlMarkupServices markupServices, MarkupPointer splitPoint) { HtmlStyleHelper htmlStyleHelper = new HtmlStyleHelper(markupServices); htmlStyleHelper.SplitInlineTags(splitPoint); }
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); }